Permalink
319 lines (275 sloc)
8.12 KB
This reverts commit d8f535b. PR-URL: #38245 Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de> Reviewed-By: Robert Nagy <ronagy@icloud.com> Reviewed-By: Richard Lau <rlau@redhat.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Zijian Liu <lxxyxzj@gmail.com> Reviewed-By: Beth Griggs <bgriggs@redhat.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Michael Dawson <midawson@redhat.com> Reviewed-By: Rich Trott <rtrott@gmail.com>
| // 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. | |
| 'use strict'; | |
| const { | |
| MathTrunc, | |
| ObjectCreate, | |
| ObjectDefineProperty, | |
| SymbolToPrimitive | |
| } = primordials; | |
| const { | |
| immediateInfo, | |
| toggleImmediateRef | |
| } = internalBinding('timers'); | |
| const L = require('internal/linkedlist'); | |
| const { | |
| async_id_symbol, | |
| Timeout, | |
| Immediate, | |
| decRefCount, | |
| immediateInfoFields: { | |
| kCount, | |
| kRefCount | |
| }, | |
| kRefed, | |
| kHasPrimitive, | |
| getTimerDuration, | |
| timerListMap, | |
| timerListQueue, | |
| immediateQueue, | |
| active, | |
| unrefActive, | |
| insert | |
| } = require('internal/timers'); | |
| const { | |
| promisify: { custom: customPromisify }, | |
| deprecate | |
| } = require('internal/util'); | |
| let debug = require('internal/util/debuglog').debuglog('timer', (fn) => { | |
| debug = fn; | |
| }); | |
| const { validateCallback } = require('internal/validators'); | |
| let timersPromises; | |
| const { | |
| destroyHooksExist, | |
| // The needed emit*() functions. | |
| emitDestroy | |
| } = require('internal/async_hooks'); | |
| // This stores all the known timer async ids to allow users to clearTimeout and | |
| // clearInterval using those ids, to match the spec and the rest of the web | |
| // platform. | |
| const knownTimersById = ObjectCreate(null); | |
| // 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 = MathTrunc(item._idleTimeout); | |
| const list = timerListMap[msecs]; | |
| if (list !== undefined && L.isEmpty(list)) { | |
| debug('unenroll: list empty'); | |
| 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; | |
| } | |
| /* | |
| * DOM-style timers | |
| */ | |
| function setTimeout(callback, after, arg1, arg2, arg3) { | |
| validateCallback(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; | |
| } | |
| ObjectDefineProperty(setTimeout, customPromisify, { | |
| enumerable: true, | |
| get() { | |
| if (!timersPromises) | |
| timersPromises = require('timers/promises'); | |
| return timersPromises.setTimeout; | |
| } | |
| }); | |
| 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); | |
| } | |
| } | |
| } | |
| function setInterval(callback, repeat, arg1, arg2, arg3) { | |
| validateCallback(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; | |
| } | |
| 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[SymbolToPrimitive] = function() { | |
| const id = this[async_id_symbol]; | |
| if (!this[kHasPrimitive]) { | |
| this[kHasPrimitive] = true; | |
| knownTimersById[id] = this; | |
| } | |
| return id; | |
| }; | |
| function setImmediate(callback, arg1, arg2, arg3) { | |
| validateCallback(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); | |
| } | |
| ObjectDefineProperty(setImmediate, customPromisify, { | |
| enumerable: true, | |
| get() { | |
| if (!timersPromises) | |
| timersPromises = require('timers/promises'); | |
| return timersPromises.setImmediate; | |
| } | |
| }); | |
| function clearImmediate(immediate) { | |
| if (!immediate || immediate._destroyed) | |
| return; | |
| immediateInfo[kCount]--; | |
| immediate._destroyed = true; | |
| if (immediate[kRefed] && --immediateInfo[kRefCount] === 0) | |
| toggleImmediateRef(false); | |
| immediate[kRefed] = null; | |
| if (destroyHooksExist() && immediate[async_id_symbol] !== undefined) { | |
| emitDestroy(immediate[async_id_symbol]); | |
| } | |
| immediate._onImmediate = null; | |
| immediateQueue.remove(immediate); | |
| } | |
| module.exports = { | |
| 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') | |
| }; |