Skip to content

Commit

Permalink
Conditionalize Promise Polyfill for Hermes
Browse files Browse the repository at this point in the history
Summary:
On Hermes, RN can directly use the Promise from global w/o the need of polyfilling it.

PromiseRejectionTrackingOptions are extracted to its own file so it can be shared by
both codepaths and preserve the behaviors that it's only imported on dev.
Some zero-overhead type gymnastics are used to flow-type it properly.

Changelog:
[General] - made promise polyfill conditionalized on Hermes

Reviewed By: cpojer

Differential Revision: D24068716

fbshipit-source-id: 3e0b1675493908324f27cc5b7300d8cc42a03acc
  • Loading branch information
Huxpro authored and facebook-github-bot committed Oct 19, 2020
1 parent 3c154c8 commit 0a28b34
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 37 deletions.
18 changes: 17 additions & 1 deletion Libraries/Core/polyfillPromise.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,20 @@ const {polyfillGlobal} = require('../Utilities/PolyfillFunctions');
* If you don't need these polyfills, don't use InitializeCore; just directly
* require the modules you need from InitializeCore for setup.
*/
polyfillGlobal('Promise', () => require('../Promise'));

// If global.Promise is provided by Hermes, we are confident that it can provide
// all the methods needed by React Native, so we can directly use it.
if (global?.HermesInternal?.hasPromise?.()) {
const HermesPromise = global.Promise;

if (__DEV__) {
if (typeof HermesPromise !== 'function') {
console.error('HermesPromise does not exist');
}
global.HermesInternal.enablePromiseRejectionTracker(
require('../promiseRejectionTrackingOptions').default,
);
}
} else {
polyfillGlobal('Promise', () => require('../Promise'));
}
39 changes: 3 additions & 36 deletions Libraries/Promise.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,9 @@ require('promise/setimmediate/done');
require('promise/setimmediate/finally');

if (__DEV__) {
require('promise/setimmediate/rejection-tracking').enable({
allRejections: true,
onUnhandled: (id, rejection = {}) => {
let message: string;
let stack: ?string;

const stringValue = Object.prototype.toString.call(rejection);
if (stringValue === '[object Error]') {
message = Error.prototype.toString.call(rejection);
const error: Error = (rejection: $FlowFixMe);
stack = error.stack;
} else {
try {
message = require('pretty-format')(rejection);
} catch {
message =
typeof rejection === 'string'
? rejection
: JSON.stringify((rejection: $FlowFixMe));
}
}

const warning =
`Possible Unhandled Promise Rejection (id: ${id}):\n` +
`${message ?? ''}\n` +
(stack == null ? '' : stack);
console.warn(warning);
},
onHandled: id => {
const warning =
`Promise Rejection Handled (id: ${id})\n` +
'This means you can ignore any previous messages of the form ' +
`"Possible Unhandled Promise Rejection (id: ${id}):"`;
console.warn(warning);
},
});
require('promise/setimmediate/rejection-tracking').enable(
require('./promiseRejectionTrackingOptions').default,
);
}

module.exports = Promise;
54 changes: 54 additions & 0 deletions Libraries/promiseRejectionTrackingOptions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict
*/

'use strict';

import typeof {enable} from 'promise/setimmediate/rejection-tracking';

type ExtractOptionsType = <P>((options?: ?P) => void) => P;

let rejectionTrackingOptions: $Call<ExtractOptionsType, enable> = {
allRejections: true,
onUnhandled: (id, rejection = {}) => {
let message: string;
let stack: ?string;

const stringValue = Object.prototype.toString.call(rejection);
if (stringValue === '[object Error]') {
message = Error.prototype.toString.call(rejection);
const error: Error = (rejection: $FlowFixMe);
stack = error.stack;
} else {
try {
message = require('pretty-format')(rejection);
} catch {
message =
typeof rejection === 'string'
? rejection
: JSON.stringify((rejection: $FlowFixMe));
}
}

const warning =
`Possible Unhandled Promise Rejection (id: ${id}):\n` +
`${message ?? ''}\n` +
(stack == null ? '' : stack);
console.warn(warning);
},
onHandled: id => {
const warning =
`Promise Rejection Handled (id: ${id})\n` +
'This means you can ignore any previous messages of the form ' +
`"Possible Unhandled Promise Rejection (id: ${id}):"`;
console.warn(warning);
},
};

export default rejectionTrackingOptions;

0 comments on commit 0a28b34

Please sign in to comment.