Files
react-native/Libraries/Core/Timers/immediateShim.js
T
Xuan Huang dc8d218077 Shim Immediate APIs when Promise is queueing to JSVM
Summary:
Changelog: [Internal]

Historically, Immediate API is implemented upon the React Native's
internal microtask-y queue (known as "immediate queue"), which
is the same queue Promise polyfill is operating on.

To make React Native suitable of using the built-in Promises from JSVMs,
which usually enqueues to the JSVM internal microtask queue and has no
access to React Native microtask-y queue, we need to migrate the
Immediate API to use the JSVM microtask queue as well to preserve the
semantics of code relies on the interleaving of promises and immediates.

To do that, this diff implement a shim layer for immediate APIs via the
new `global.queueMicrotask` API (which enqueues to JSVM) in JS, by wrapping
the immediate callback into a "microtask callback", which validate the
`immediate ID` against `clearedImmediate` Set before invoking it.

Reviewed By: RSNara

Differential Revision: D29845305

fbshipit-source-id: c2ed3fed426a5316b1e0dfbfaad51706d1765d4d
2021-07-28 13:37:54 -07:00

68 lines
1.6 KiB
JavaScript

/**
* 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
*/
'use strict';
// Globally Unique Immediate ID.
let GUIID = 1;
// A global set of the currently cleared immediates.
const clearedImmediates: Set<number> = new Set();
/**
* Shim the setImmediate API on top of queueMicrotask.
* @param {function} func Callback to be invoked before the end of the
* current JavaScript execution loop.
*/
function setImmediate(callback: Function, ...args: any): number {
if (arguments.length < 1) {
throw new TypeError(
'setImmediate must be called with at least one argument (a function to call)',
);
}
if (typeof callback !== 'function') {
throw new TypeError(
'The first argument to setImmediate must be a function.',
);
}
const id = GUIID++;
// This is an edgey case in which the sequentially assigned ID has been
// "guessed" and "cleared" ahead of time, so we need to clear it up first.
if (clearedImmediates.has(id)) {
clearedImmediates.delete(id);
}
global.queueMicrotask(() => {
if (!clearedImmediates.has(id)) {
callback.apply(undefined, args);
} else {
// Free up the Set entry.
clearedImmediates.delete(id);
}
});
return id;
}
/**
* @param {number} immediateID The ID of the immediate to be clearred.
*/
function clearImmediate(immediateID: number) {
clearedImmediates.add(immediateID);
}
const immediateShim = {
setImmediate: setImmediate,
clearImmediate: clearImmediate,
};
module.exports = immediateShim;