diff options
author | Yoshiya Hinosawa <stibium121@gmail.com> | 2021-12-09 17:00:55 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-09 17:00:55 +0900 |
commit | 69ad5f0e7879e9555f949c9b5eb48440cd9e9fdc (patch) | |
tree | ca01e028d63b038258c48ce1e28c2725a887f27a /ext/timers/01_timers.js | |
parent | 1507b8c9843262d6514ed61fdba115671dfb7bfe (diff) |
feat(ext/timers): add refTimer, unrefTimer API (#12953)
Diffstat (limited to 'ext/timers/01_timers.js')
-rw-r--r-- | ext/timers/01_timers.js | 56 |
1 files changed, 43 insertions, 13 deletions
diff --git a/ext/timers/01_timers.js b/ext/timers/01_timers.js index ee3d85661..6bed6ba4c 100644 --- a/ext/timers/01_timers.js +++ b/ext/timers/01_timers.js @@ -16,6 +16,7 @@ // deno-lint-ignore camelcase NumberPOSITIVE_INFINITY, PromisePrototypeThen, + SymbolFor, TypeError, } = window.__bootstrap.primordials; const { webidl } = window.__bootstrap; @@ -87,7 +88,7 @@ * The keys in this map correspond to the key ID's in the spec's map of active * timers. The values are the timeout's cancel rid. * - * @type {Map<number, number>} + * @type {Map<number, { cancelRid: number, isRef: boolean, promiseId: number }>} */ const activeTimers = new Map(); @@ -112,20 +113,21 @@ // previousId be an implementation-defined integer than is greater than zero // and does not already exist in global's map of active timers. let id; - let cancelRid; + let timerInfo; if (prevId !== undefined) { // `prevId` is only passed for follow-up calls on intervals assert(repeat); id = prevId; - cancelRid = MapPrototypeGet(activeTimers, id); + timerInfo = MapPrototypeGet(activeTimers, id); } else { // TODO(@andreubotella): Deal with overflow. // https://github.com/whatwg/html/issues/7358 id = nextId++; - cancelRid = core.opSync("op_timer_handle"); + const cancelRid = core.opSync("op_timer_handle"); + timerInfo = { cancelRid, isRef: true, promiseId: -1 }; // Step 4 in "run steps after a timeout". - MapPrototypeSet(activeTimers, id, cancelRid); + MapPrototypeSet(activeTimers, id, timerInfo); } // 3. If the surrounding agent's event loop's currently running task is a @@ -175,7 +177,7 @@ } } else { // 6. Otherwise, remove global's map of active timers[id]. - core.tryClose(cancelRid); + core.tryClose(timerInfo.cancelRid); MapPrototypeDelete(activeTimers, id); } }, @@ -192,7 +194,7 @@ runAfterTimeout( () => ArrayPrototypePush(timerTasks, task), timeout, - cancelRid, + timerInfo, ); return id; @@ -219,9 +221,17 @@ * @param {() => void} cb Will be run after the timeout, if it hasn't been * cancelled. * @param {number} millis - * @param {number} cancelRid + * @param {{ cancelRid: number, isRef: boolean, promiseId: number }} timerInfo */ - function runAfterTimeout(cb, millis, cancelRid) { + function runAfterTimeout(cb, millis, timerInfo) { + const cancelRid = timerInfo.cancelRid; + const sleepPromise = core.opAsync("op_sleep", millis, cancelRid); + timerInfo.promiseId = + sleepPromise[SymbolFor("Deno.core.internalPromiseId")]; + if (!timerInfo.isRef) { + core.unrefOp(timerInfo.promiseId); + } + /** @type {ScheduledTimer} */ const timerObject = { millis, @@ -242,7 +252,7 @@ // 1. PromisePrototypeThen( - core.opAsync("op_sleep", millis, cancelRid), + sleepPromise, () => { // 2. Wait until any invocations of this algorithm that had the same // global and orderingIdentifier, that started before this one, and @@ -334,9 +344,9 @@ function clearTimeout(id = 0) { checkThis(this); id = webidl.converters.long(id); - const cancelHandle = MapPrototypeGet(activeTimers, id); - if (cancelHandle !== undefined) { - core.tryClose(cancelHandle); + const timerInfo = MapPrototypeGet(activeTimers, id); + if (timerInfo !== undefined) { + core.tryClose(timerInfo.cancelRid); MapPrototypeDelete(activeTimers, id); } } @@ -346,6 +356,24 @@ clearTimeout(id); } + function refTimer(id) { + const timerInfo = MapPrototypeGet(activeTimers, id); + if (timerInfo === undefined || timerInfo.isRef) { + return; + } + timerInfo.isRef = true; + core.refOp(timerInfo.promiseId); + } + + function unrefTimer(id) { + const timerInfo = MapPrototypeGet(activeTimers, id); + if (timerInfo === undefined || !timerInfo.isRef) { + return; + } + timerInfo.isRef = false; + core.unrefOp(timerInfo.promiseId); + } + window.__bootstrap.timers = { setTimeout, setInterval, @@ -354,5 +382,7 @@ handleTimerMacrotask, opNow, sleepSync, + refTimer, + unrefTimer, }; })(this); |