UNPKG

nstdlib-nightly

Version:

Node.js standard library converted to runtime-agnostic ES modules.

380 lines (335 loc) 9.95 kB
// Source: https://github.com/nodejs/node/blob/65eff1eb/lib/timers.js import * as __hoisted_timers_promises__ from "nstdlib/lib/timers/promises"; import * as binding from "nstdlib/stub/binding/timers"; import * as L from "nstdlib/lib/internal/linkedlist"; import { async_id_symbol, Timeout, Immediate, decRefCount, immediateInfoFields as __immediateInfoFields__, kRefed, kHasPrimitive, getTimerDuration, timerListMap, timerListQueue, immediateQueue, active, unrefActive, insert, knownTimersById, } from "nstdlib/lib/internal/timers"; import { promisify as __promisify__, deprecate, } from "nstdlib/lib/internal/util"; import { validateFunction } from "nstdlib/lib/internal/validators"; import { destroyHooksExist, // The needed emit*() functions. emitDestroy, } from "nstdlib/lib/internal/async_hooks"; // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. const { immediateInfo } = binding; const { kCount, kRefCount } = __immediateInfoFields__; const { custom: customPromisify } = __promisify__; let timersPromises; let timers; // Remove a timer. Cancels the timeout and resets the relevant timer properties. function unenroll(item) { if (item._destroyed) return; item._destroyed = true; if (item[kHasPrimitive]) delete knownTimersById[item[async_id_symbol]]; // Fewer checks may be possible, but these cover everything. if (destroyHooksExist() && item[async_id_symbol] !== undefined) emitDestroy(item[async_id_symbol]); L.remove(item); // We only delete refed lists because unrefed ones are incredibly likely // to come from http and be recreated shortly after. // TODO: Long-term this could instead be handled by creating an internal // clearTimeout that makes it clear that the list should not be deleted. // That function could then be used by http and other similar modules. if (item[kRefed]) { // Compliment truncation during insert(). const msecs = Math.trunc(item._idleTimeout); const list = timerListMap[msecs]; if (list !== undefined && L.isEmpty(list)) { { /* debug */ } timerListQueue.removeAt(list.priorityQueuePosition); delete timerListMap[list.msecs]; } decRefCount(); } // If active is called later, then we want to make sure not to insert again item._idleTimeout = -1; } // Make a regular object able to act as a timer by setting some properties. // This function does not start the timer, see `active()`. // Using existing objects as timers slightly reduces object overhead. function enroll(item, msecs) { msecs = getTimerDuration(msecs, "msecs"); // If this item was already in a list somewhere // then we should unenroll it from that if (item._idleNext) unenroll(item); L.init(item); item._idleTimeout = msecs; } /** * Schedules the execution of a one-time `callback` * after `after` milliseconds. * @param {Function} callback * @param {number} [after] * @param {any} [arg1] * @param {any} [arg2] * @param {any} [arg3] * @returns {Timeout} */ function setTimeout(callback, after, arg1, arg2, arg3) { validateFunction(callback, "callback"); let i, args; switch (arguments.length) { // fast cases case 1: case 2: break; case 3: args = [arg1]; break; case 4: args = [arg1, arg2]; break; default: args = [arg1, arg2, arg3]; for (i = 5; i < arguments.length; i++) { // Extend array dynamically, makes .apply run much faster in v6.0.0 args[i - 2] = arguments[i]; } break; } const timeout = new Timeout(callback, after, args, false, true); insert(timeout, timeout._idleTimeout); return timeout; } Object.defineProperty(setTimeout, customPromisify, { __proto__: null, enumerable: true, get() { if (!timersPromises) timersPromises = __hoisted_timers_promises__; return timersPromises.setTimeout; }, }); /** * Cancels a timeout. * @param {Timeout | string | number} timer * @returns {void} */ function clearTimeout(timer) { if (timer && timer._onTimeout) { timer._onTimeout = null; unenroll(timer); return; } if (typeof timer === "number" || typeof timer === "string") { const timerInstance = knownTimersById[timer]; if (timerInstance !== undefined) { timerInstance._onTimeout = null; unenroll(timerInstance); } } } /** * Schedules repeated execution of `callback` * every `repeat` milliseconds. * @param {Function} callback * @param {number} [repeat] * @param {any} [arg1] * @param {any} [arg2] * @param {any} [arg3] * @returns {Timeout} */ function setInterval(callback, repeat, arg1, arg2, arg3) { validateFunction(callback, "callback"); let i, args; switch (arguments.length) { // fast cases case 1: case 2: break; case 3: args = [arg1]; break; case 4: args = [arg1, arg2]; break; default: args = [arg1, arg2, arg3]; for (i = 5; i < arguments.length; i++) { // Extend array dynamically, makes .apply run much faster in v6.0.0 args[i - 2] = arguments[i]; } break; } const timeout = new Timeout(callback, repeat, args, true, true); insert(timeout, timeout._idleTimeout); return timeout; } /** * Cancels an interval. * @param {Timeout | string | number} timer * @returns {void} */ function clearInterval(timer) { // clearTimeout and clearInterval can be used to clear timers created from // both setTimeout and setInterval, as specified by HTML Living Standard: // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-setinterval clearTimeout(timer); } Timeout.prototype.close = function () { clearTimeout(this); return this; }; Timeout.prototype[Symbol.for("nodejs.dispose")] = function () { clearTimeout(this); }; /** * Coerces a `Timeout` to a primitive. * @returns {number} */ Timeout.prototype[Symbol.toPrimitive] = function () { const id = this[async_id_symbol]; if (!this[kHasPrimitive]) { this[kHasPrimitive] = true; knownTimersById[id] = this; } return id; }; /** * Schedules the immediate execution of `callback` * after I/O events' callbacks. * @param {Function} callback * @param {any} [arg1] * @param {any} [arg2] * @param {any} [arg3] * @returns {Immediate} */ function setImmediate(callback, arg1, arg2, arg3) { validateFunction(callback, "callback"); let i, args; switch (arguments.length) { // fast cases case 1: break; case 2: args = [arg1]; break; case 3: args = [arg1, arg2]; break; default: args = [arg1, arg2, arg3]; for (i = 4; i < arguments.length; i++) { // Extend array dynamically, makes .apply run much faster in v6.0.0 args[i - 1] = arguments[i]; } break; } return new Immediate(callback, args); } Object.defineProperty(setImmediate, customPromisify, { __proto__: null, enumerable: true, get() { if (!timersPromises) timersPromises = __hoisted_timers_promises__; return timersPromises.setImmediate; }, }); /** * Cancels an immediate. * @param {Immediate} immediate * @returns {void} */ function clearImmediate(immediate) { if (!immediate || immediate._destroyed) return; immediateInfo[kCount]--; immediate._destroyed = true; if (immediate[kRefed] && --immediateInfo[kRefCount] === 0) { // We need to use the binding as the receiver for fast API calls. binding.toggleImmediateRef(false); } immediate[kRefed] = null; if (destroyHooksExist() && immediate[async_id_symbol] !== undefined) { emitDestroy(immediate[async_id_symbol]); } immediate._onImmediate = null; immediateQueue.remove(immediate); } Immediate.prototype[Symbol.for("nodejs.dispose")] = function () { clearImmediate(this); }; export default timers = { setTimeout, clearTimeout, setImmediate, clearImmediate, setInterval, clearInterval, _unrefActive: deprecate( unrefActive, "timers._unrefActive() is deprecated." + " Please use timeout.refresh() instead.", "DEP0127", ), active: deprecate( active, "timers.active() is deprecated. Please use timeout.refresh() instead.", "DEP0126", ), unenroll: deprecate( unenroll, "timers.unenroll() is deprecated. Please use clearTimeout instead.", "DEP0096", ), enroll: deprecate( enroll, "timers.enroll() is deprecated. Please use setTimeout instead.", "DEP0095", ), }; Object.defineProperties(timers, { promises: { __proto__: null, configurable: true, enumerable: true, get() { timersPromises ??= __hoisted_timers_promises__; return timersPromises; }, }, }); export { setTimeout }; export { clearTimeout }; export { setImmediate }; export { clearImmediate }; export { setInterval }; export { clearInterval };