RN: Lazily Symbolicate Warnings

Summary:
Currently, every warning triggers a packager request to symbolicate the stack trace. If there happens to be a lot of warnings or if the packager or device are pretty busy (or low powered), this can cause a significant delay in responsiveness (and development velocity).

This fixes the issue by only symbolicating warnings when users inspect them.

Reviewed By: sahrens

Differential Revision: D3448032

fbshipit-source-id: d6154f336ed34c15f99170da013ae3ff1f1ef075
This commit is contained in:
Tim Yung 2016-06-16 19:03:11 -07:00 committed by Facebook Github Bot 6
parent 1731598428
commit f60e80d89d
1 changed files with 47 additions and 20 deletions

View File

@ -16,8 +16,9 @@ const EventEmitter = require('EventEmitter');
const Platform = require('Platform');
const React = require('React');
const StyleSheet = require('StyleSheet');
const symbolicateStackTrace = require('symbolicateStackTrace');
const infoLog = require('infoLog');
const parseErrorStack = require('parseErrorStack');
const symbolicateStackTrace = require('symbolicateStackTrace');
import type EmitterSubscription from 'EmitterSubscription';
import type {StackFrame} from 'parseErrorStack';
@ -25,6 +26,7 @@ import type {StackFrame} from 'parseErrorStack';
type WarningInfo = {
count: number;
stacktrace: Array<StackFrame>;
symbolicated: boolean;
};
const _warningEmitter = new EventEmitter();
@ -77,7 +79,7 @@ if (__DEV__) {
* @return {string} the replaced string
*/
function sprintf(format, ...args) {
var index = 0;
let index = 0;
return format.replace(/%s/g, match => args[index++]);
}
@ -91,28 +93,46 @@ function updateWarningMap(format, ...args): void {
...args.slice(argCount).map(stringifySafe),
].join(' ');
var warningInfo = _warningMap.get(warning);
const warningInfo = _warningMap.get(warning);
if (warningInfo) {
warningInfo.count += 1;
} else {
warningInfo = {count: 1, stacktrace: []};
const error: any = new Error();
error.framesToPop = 2;
_warningMap.set(warning, {
count: 1,
stacktrace: parseErrorStack(error),
symbolicated: false,
});
}
_warningMap.set(warning, warningInfo);
_warningEmitter.emit('warning', _warningMap);
}
var error : any = new Error();
error.framesToPop = 2;
function ensureSymbolicatedWarning(warning: string): void {
const prevWarningInfo = _warningMap.get(warning);
if (!prevWarningInfo || prevWarningInfo.symbolicated) {
return;
}
prevWarningInfo.symbolicated = true;
symbolicateStackTrace(parseErrorStack(error)).then(stack => {
warningInfo = _warningMap.get(warning);
if (warningInfo) {
warningInfo.stacktrace = stack;
_warningMap.set(warning, warningInfo);
_warningEmitter.emit('warning', _warningMap);
symbolicateStackTrace(prevWarningInfo.stacktrace).then(
stack => {
const nextWarningInfo = _warningMap.get(warning);
if (nextWarningInfo) {
nextWarningInfo.stacktrace = stack;
_warningEmitter.emit('warning', _warningMap);
}
},
error => {
const nextWarningInfo = _warningMap.get(warning);
if (nextWarningInfo) {
infoLog('Failed to symbolicate warning, "%s":', warning, error);
_warningEmitter.emit('warning', _warningMap);
}
}
}, () => { /* Do nothing when can't load source map */ });
);
}
function isWarningIgnored(warning: string): boolean {
@ -182,7 +202,7 @@ const WarningInspector = ({
let stacktraceList;
if (stacktraceVisible && stacktrace) {
stacktraceList = (
<View>
<View style={styles.stacktraceList}>
{stacktrace.map((frame, ii) => <StackRow frame={frame} key={ii} />)}
</View>
);
@ -203,7 +223,7 @@ const WarningInspector = ({
style={styles.stacktraceButton}
underlayColor="transparent">
<Text style={styles.inspectorButtonText}>
{stacktraceVisible ? 'Hide' : 'Show'} stacktrace
{stacktraceVisible ? 'Hide' : 'Show'} Stacktrace
</Text>
</TouchableHighlight>
</View>
@ -280,6 +300,13 @@ class YellowBox extends React.Component {
});
}
componentDidUpdate() {
const {inspecting} = this.state;
if (inspecting != null) {
ensureSymbolicatedWarning(inspecting);
}
}
componentWillUnmount() {
if (this._listener) {
this._listener.remove();
@ -355,9 +382,6 @@ var styles = StyleSheet.create({
backgroundColor: backgroundColor(0.95),
flex: 1,
},
inspectorContainer: {
flex: 1,
},
inspectorButtons: {
flexDirection: 'row',
position: 'absolute',
@ -374,6 +398,9 @@ var styles = StyleSheet.create({
flex: 1,
padding: 5,
},
stacktraceList: {
paddingBottom: 5,
},
inspectorButtonText: {
color: textColor,
fontSize: 14,