-
Notifications
You must be signed in to change notification settings - Fork 46.9k
Commit
* Show React events in the timeline when ReactPerf is active This currently only seems to work on Chrome. * Address Chrome issue (cherry picked from commit 0a248ee)
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -192,6 +192,63 @@ function resumeCurrentLifeCycleTimer() { | |
currentTimerType = timerType; | ||
} | ||
|
||
var lastMarkTimeStamp = null; | ||
var canUsePerformanceMeasure = | ||
typeof performance !== 'undefined' && | ||
typeof performance.mark === 'function' && | ||
typeof performance.clearMarks === 'function' && | ||
typeof performance.measure === 'function' && | ||
typeof performance.clearMeasures === 'function'; | ||
|
||
function shouldMark(debugID) { | ||
if (!isProfiling || !canUsePerformanceMeasure) { | ||
return false; | ||
} | ||
var element = ReactComponentTreeHook.getElement(debugID); | ||
if (element == null || typeof element !== 'object') { | ||
return false; | ||
} | ||
var isHostElement = typeof element.type === 'string'; | ||
if (isHostElement) { | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
function markBegin(debugID, markType) { | ||
if (!shouldMark(debugID)) { | ||
return; | ||
} | ||
|
||
var markName = `${debugID}::${markType}`; | ||
lastMarkTimeStamp = performanceNow(); | ||
performance.mark(markName); | ||
} | ||
|
||
function markEnd(debugID, markType) { | ||
if (!shouldMark(debugID)) { | ||
return; | ||
} | ||
|
||
var markName = `${debugID}::${markType}`; | ||
var displayName = ReactComponentTreeHook.getDisplayName(debugID); | ||
|
||
// Chrome has an issue of dropping markers recorded too fast: | ||
// https://bugs.chromium.org/p/chromium/issues/detail?id=640652 | ||
// To work around this, we will not report very small measurements. | ||
// I determined the magic number by tweaking it back and forth. | ||
// 0.05ms was enough to prevent the issue, but I set it to 0.1ms to be safe. | ||
// When the bug is fixed, we can `measure()` unconditionally if we want to. | ||
var timeStamp = performanceNow(); | ||
if (timeStamp - lastMarkTimeStamp > 0.1) { | ||
var measurementName = `${displayName} [${markType}]`; | ||
performance.measure(measurementName, markName); | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
gaearon
Author
Collaborator
|
||
} | ||
|
||
performance.clearMarks(markName); | ||
performance.clearMeasures(measurementName); | ||
} | ||
|
||
var ReactDebugTool = { | ||
addHook(hook) { | ||
hooks.push(hook); | ||
|
@@ -244,11 +301,13 @@ var ReactDebugTool = { | |
onBeginLifeCycleTimer(debugID, timerType) { | ||
checkDebugID(debugID); | ||
emitEvent('onBeginLifeCycleTimer', debugID, timerType); | ||
markBegin(debugID, timerType); | ||
beginLifeCycleTimer(debugID, timerType); | ||
}, | ||
onEndLifeCycleTimer(debugID, timerType) { | ||
checkDebugID(debugID); | ||
endLifeCycleTimer(debugID, timerType); | ||
markEnd(debugID, timerType); | ||
emitEvent('onEndLifeCycleTimer', debugID, timerType); | ||
}, | ||
onBeginProcessingChildContext() { | ||
|
@@ -273,25 +332,31 @@ var ReactDebugTool = { | |
checkDebugID(debugID); | ||
checkDebugID(parentDebugID, true); | ||
emitEvent('onBeforeMountComponent', debugID, element, parentDebugID); | ||
markBegin(debugID, 'mount'); | ||
}, | ||
onMountComponent(debugID) { | ||
checkDebugID(debugID); | ||
markEnd(debugID, 'mount'); | ||
emitEvent('onMountComponent', debugID); | ||
}, | ||
onBeforeUpdateComponent(debugID, element) { | ||
checkDebugID(debugID); | ||
emitEvent('onBeforeUpdateComponent', debugID, element); | ||
markBegin(debugID, 'update'); | ||
}, | ||
onUpdateComponent(debugID) { | ||
checkDebugID(debugID); | ||
markEnd(debugID, 'update'); | ||
emitEvent('onUpdateComponent', debugID); | ||
}, | ||
onBeforeUnmountComponent(debugID) { | ||
checkDebugID(debugID); | ||
emitEvent('onBeforeUnmountComponent', debugID); | ||
markBegin(debugID, 'unmount'); | ||
}, | ||
onUnmountComponent(debugID) { | ||
checkDebugID(debugID); | ||
markEnd(debugID, 'unmount'); | ||
emitEvent('onUnmountComponent', debugID); | ||
}, | ||
onTestEvent() { | ||
|
Hey @gaearon it's nice to interact on code from the hot reload and redux master himself!
I am having issues with this performance.measure where it cannot find the starting mark in my application. I am on version 15.4.2 of react and nothing has changed with this in current master it is still not handling errors if an application is setup in a way that confuses this logger's "start measurement" where the key of the measurementName does not exist upon calling markEnd.
Basically, this breaks my entire app certain modules because it cannot render. Wouldn't a try/catch be a nice thing here if somehow an error occurs, the app will just log that an error occurred in performance benchmarking the renders and the developer just has his app rendering just fine, but just has an error.
Rather the way it is coded, its a fatal error and uncaught exception so the entire render fails to even load because this is not handled with a try/catch.
Any thoughts on adding this? For now I can just turn off performance rendering for developers or fork this version of react to put a try/catch in myself until this is handled better. In my opinion, a performance monitoring solution should never affect an apps render since all of these are just logged and the core library should never have uncaught exceptions raising up the stack and causing render to fail.