Skip to content

Commit be189cd

Browse files
Huxprofacebook-github-bot
authored andcommitted
Introduce queueMicrotask API
Summary: Changelog: [General][Added] - Add global.queueMicrotask `queueMicrotask` is a relatively recent API defined in the WHATWG HTML spec and it's been widely adopted by all web browsers and Node.js. This diff introduced it to React Native by polyfilling it via a lazily-allocated resolved Promise, or calling directly into a fast path provided by Hermes. Reviewed By: RSNara Differential Revision: D29838852 fbshipit-source-id: 8c4378b1b713fb8b0da5e67f92ba2ea9838766f7
1 parent 3081db2 commit be189cd

File tree

2 files changed

+69
-2
lines changed

2 files changed

+69
-2
lines changed
+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @format
8+
* @flow
9+
*/
10+
11+
'use strict';
12+
13+
let resolvedPromise;
14+
15+
/**
16+
* Polyfill for the microtask queuening API defined by WHATWG HTMP spec.
17+
* https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-queuemicrotask
18+
*
19+
* The method must queue a microtask to invoke @param {function} callback, and
20+
* if the callback throws an exception, report the exception.
21+
*/
22+
export default function queueMicrotask(callback: Function) {
23+
if (arguments.length < 1) {
24+
throw new TypeError(
25+
'queueMicrotask must be called with at least one argument (a function to call)',
26+
);
27+
}
28+
if (typeof callback !== 'function') {
29+
throw new TypeError('The argument to queueMicrotask must be a function.');
30+
}
31+
32+
// Try to reuse a lazily allocated resolved promise from closure.
33+
(resolvedPromise || (resolvedPromise = Promise.resolve()))
34+
.then(callback)
35+
.catch(error =>
36+
// Report the exception until the next tick.
37+
setTimeout(() => {
38+
throw error;
39+
}, 0),
40+
);
41+
}

Libraries/Core/setUpTimers.js

+28-2
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,21 @@
1010

1111
'use strict';
1212

13+
const {polyfillGlobal} = require('../Utilities/PolyfillFunctions');
14+
15+
if (__DEV__) {
16+
if (typeof global.Promise !== 'function') {
17+
console.error('Promise should exist before setting up timers.');
18+
}
19+
}
20+
21+
// Currently, Hermes `Promise` is implemented via Internal Bytecode.
22+
const hasHermesPromiseQueuedToJSVM =
23+
global?.HermesInternal?.hasPromise?.() &&
24+
global?.HermesInternal?.useEngineQueue?.();
25+
1326
// In bridgeless mode, timers are host functions installed from cpp.
1427
if (!global.RN$Bridgeless) {
15-
const {polyfillGlobal} = require('../Utilities/PolyfillFunctions');
16-
1728
/**
1829
* Set up timers.
1930
* You can use this module directly, or just require InitializeCore.
@@ -42,3 +53,18 @@ if (!global.RN$Bridgeless) {
4253
() => require('./Timers/JSTimers').clearReactNativeMicrotask,
4354
);
4455
}
56+
57+
/**
58+
* Set up the microtask queueing API, which is required to use the same
59+
* microtask queue as the Promise.
60+
*/
61+
if (hasHermesPromiseQueuedToJSVM) {
62+
// Fast path for Hermes.
63+
polyfillGlobal('queueMicrotask', () => global.HermesInternal.enqueueJob);
64+
} else {
65+
// Polyfill it with promise (regardless it's polyfiled or native) otherwise.
66+
polyfillGlobal(
67+
'queueMicrotask',
68+
() => require('./Timers/queueMicrotask.js').default,
69+
);
70+
}

0 commit comments

Comments
 (0)