mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Summary:
This PR fixes logging of rejections, which stopped working with the transition from using `LogBox` for warnings to directing users to use React Native Debugger, where warnings can be viewed in the `Console` tab.
Rejected promises before this PR used `LogBox.addLog` with the `level: warn` directly without `console.warn`, which notified users to open debugger to view a warning (after rejected promise) without actually printing any warnings to the console.
This PR uses `ExceptionsManager.handleException(error, false /* isFatal */);` for promise rejections that correctly raising an error to the console if needed.
### Rejected Promise in Chrome
Displaying the error as long as it's uncaught in the form:
`Uncaught (in promise) Error`
and if there's a message in that error:
`Uncaught (in promise) Error: ${message}`
once the error is handled, this error disappears:
{F1978806409}
This is done with `Runtime.exceptionThrown`, and `Runtime.exceptionRevoked`:
{F1979815326}
## Changelog:
[General][Breaking] unhandled promises are now handled by ExceptionsManager.handleException, instead of being swallowed as Logbox Warnings.
----
This is a breaking change because we changed the wording for these errors and because some systems (like Sentry) might start monitoring a new set of errors when this code is adopted.
Pull Request resolved: https://github.com/facebook/react-native/pull/51594
Test Plan:
Use `Promise.reject` and observe that the rejection is now shown symbolicated in LogBox and also printed in React Native Debugger Console.
```
<Button
title="Uncaught Promise Rejection"
onPress={() => {
const err = new Error('test error');
err.cause = new Error('cause');
const promise = Promise.resolve().then(() => {
throw err;
// also test with throwing a string / object:
// throw 'aa';
// throw {test: 'object'};
// return Promise.reject();
});
setTimeout(() => {
promise.catch(e => {
console.log('promise error caught', e);
});
}, 4000);
}}
/>
```
### Before
There's no indication whatsoever there's an uncaught promise.
### After
An error is logged:
Error-
{F1979749366}
Text-
{F1979749350}
Object-
{F1979749351}
Promise.reject() or undefined-
{F1979749826}
Reviewed By: hoxyq
Differential Revision: D75442651
Pulled By: vzaidman
fbshipit-source-id: bf6c56e643f03997f5a604b85c543aad62648a29
59 lines
1.6 KiB
JavaScript
59 lines
1.6 KiB
JavaScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @flow strict
|
|
* @format
|
|
*/
|
|
|
|
import typeof {enable} from 'promise/setimmediate/rejection-tracking';
|
|
|
|
import ExceptionsManager from './Core/ExceptionsManager';
|
|
|
|
let rejectionTrackingOptions: $NonMaybeType<Parameters<enable>[0]> = {
|
|
allRejections: true,
|
|
onUnhandled: (id, rejection) => {
|
|
let message: string;
|
|
|
|
if (rejection === undefined) {
|
|
message = '';
|
|
} else if (
|
|
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
|
|
Object.prototype.toString.call(rejection) === '[object Error]'
|
|
) {
|
|
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
|
|
message = Error.prototype.toString.call(rejection);
|
|
} else {
|
|
try {
|
|
message = require('pretty-format').format(rejection);
|
|
} catch {
|
|
message =
|
|
typeof rejection === 'string'
|
|
? rejection
|
|
: JSON.stringify((rejection: $FlowFixMe));
|
|
}
|
|
}
|
|
|
|
ExceptionsManager.handleException(
|
|
new Error(
|
|
`Uncaught (in promise, id: ${id})${message ? `: "${message}"` : ''}`,
|
|
{
|
|
cause: rejection,
|
|
},
|
|
),
|
|
false /* isFatal */,
|
|
);
|
|
},
|
|
onHandled: id => {
|
|
const warning =
|
|
`Promise rejection handled (id: ${id})\n` +
|
|
'This means you can ignore any previous messages of the form ' +
|
|
`"Uncaught (in promise, id: ${id})"`;
|
|
console.warn(warning);
|
|
},
|
|
};
|
|
|
|
export default rejectionTrackingOptions;
|