mirror of
https://github.com/denoland/deno.git
synced 2024-11-26 16:09:27 -05:00
refactor: use primordials for extensions/timers (#11256)
This commit is contained in:
parent
060dd3ae82
commit
e0f67098aa
2 changed files with 71 additions and 36 deletions
|
@ -3,6 +3,24 @@
|
|||
|
||||
((window) => {
|
||||
const core = window.Deno.core;
|
||||
const {
|
||||
ArrayPrototypeIndexOf,
|
||||
ArrayPrototypePush,
|
||||
ArrayPrototypeShift,
|
||||
ArrayPrototypeSplice,
|
||||
DateNow,
|
||||
Error,
|
||||
FunctionPrototypeBind,
|
||||
Map,
|
||||
MapPrototypeDelete,
|
||||
MapPrototypeGet,
|
||||
MapPrototypeHas,
|
||||
MapPrototypeSet,
|
||||
MathMax,
|
||||
Number,
|
||||
String,
|
||||
TypeError,
|
||||
} = window.__bootstrap.primordials;
|
||||
|
||||
// Shamelessly cribbed from extensions/fetch/11_streams.js
|
||||
class AssertionError extends Error {
|
||||
|
@ -290,7 +308,6 @@
|
|||
}
|
||||
|
||||
const { console } = globalThis;
|
||||
const OriginalDateNow = Date.now;
|
||||
|
||||
// Timeout values > TIMEOUT_MAX are set to 1.
|
||||
const TIMEOUT_MAX = 2 ** 31 - 1;
|
||||
|
@ -318,7 +335,7 @@
|
|||
* before next macrotask timer callback is invoked. */
|
||||
function handleTimerMacrotask() {
|
||||
if (pendingFireTimers.length > 0) {
|
||||
fire(pendingFireTimers.shift());
|
||||
fire(ArrayPrototypeShift(pendingFireTimers));
|
||||
return pendingFireTimers.length === 0;
|
||||
}
|
||||
return true;
|
||||
|
@ -348,7 +365,7 @@
|
|||
}
|
||||
|
||||
function prepareReadyTimers() {
|
||||
const now = OriginalDateNow();
|
||||
const now = DateNow();
|
||||
// Bail out if we're not expecting the global timer to fire.
|
||||
if (globalTimeoutDue === null || pendingEvents > 0) {
|
||||
return;
|
||||
|
@ -363,7 +380,7 @@
|
|||
// With the list dropped, the timer is no longer scheduled.
|
||||
timer.scheduled = false;
|
||||
// Place the callback to pending timers to fire.
|
||||
pendingFireTimers.push(timer);
|
||||
ArrayPrototypePush(pendingFireTimers, timer);
|
||||
}
|
||||
}
|
||||
setOrClearGlobalTimeout(nextDueNode && nextDueNode.due, now);
|
||||
|
@ -388,7 +405,7 @@
|
|||
dueNode = maybeNewDueNode;
|
||||
}
|
||||
// Append the newly scheduled timer to the list and mark it as scheduled.
|
||||
dueNode.timers.push(timer);
|
||||
ArrayPrototypePush(dueNode.timers, timer);
|
||||
timer.scheduled = true;
|
||||
// If the new timer is scheduled to fire before any timer that existed before,
|
||||
// update the global timeout to reflect this.
|
||||
|
@ -402,8 +419,8 @@
|
|||
// If either is true, they are not in tree, and their idMap entry
|
||||
// will be deleted soon. Remove it from queue.
|
||||
let index = -1;
|
||||
if ((index = pendingFireTimers.indexOf(timer)) >= 0) {
|
||||
pendingFireTimers.splice(index);
|
||||
if ((index = ArrayPrototypeIndexOf(pendingFireTimers, timer)) >= 0) {
|
||||
ArrayPrototypeSplice(pendingFireTimers, index);
|
||||
return;
|
||||
}
|
||||
// If timer is not in the 2 pending queues and is unscheduled,
|
||||
|
@ -424,33 +441,33 @@
|
|||
const nextDueNode = dueTree.min();
|
||||
setOrClearGlobalTimeout(
|
||||
nextDueNode && nextDueNode.due,
|
||||
OriginalDateNow(),
|
||||
DateNow(),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Multiple timers that are due at the same point in time.
|
||||
// Remove this timer from the list.
|
||||
const index = list.indexOf(timer);
|
||||
const index = ArrayPrototypeIndexOf(list, timer);
|
||||
assert(index > -1);
|
||||
list.splice(index, 1);
|
||||
ArrayPrototypeSplice(list, index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
function fire(timer) {
|
||||
// If the timer isn't found in the ID map, that means it has been cancelled
|
||||
// between the timer firing and the promise callback (this function).
|
||||
if (!idMap.has(timer.id)) {
|
||||
if (!MapPrototypeHas(idMap, timer.id)) {
|
||||
return;
|
||||
}
|
||||
// Reschedule the timer if it is a repeating one, otherwise drop it.
|
||||
if (!timer.repeat) {
|
||||
// One-shot timer: remove the timer from this id-to-timer map.
|
||||
idMap.delete(timer.id);
|
||||
MapPrototypeDelete(idMap, timer.id);
|
||||
} else {
|
||||
// Interval timer: compute when timer was supposed to fire next.
|
||||
// However make sure to never schedule the next interval in the past.
|
||||
const now = OriginalDateNow();
|
||||
timer.due = Math.max(now, timer.due + timer.delay);
|
||||
const now = DateNow();
|
||||
timer.due = MathMax(now, timer.due + timer.delay);
|
||||
schedule(timer, now);
|
||||
}
|
||||
// Call the user callback. Intermediate assignment is to avoid leaking `this`
|
||||
|
@ -480,7 +497,7 @@
|
|||
let callback;
|
||||
|
||||
if ("function" === typeof cb) {
|
||||
callback = Function.prototype.bind.call(cb, globalThis, ...args);
|
||||
callback = FunctionPrototypeBind(cb, globalThis, ...args);
|
||||
} else {
|
||||
callback = String(cb);
|
||||
args = []; // args are ignored
|
||||
|
@ -488,7 +505,7 @@
|
|||
// In the browser, the delay value must be coercible to an integer between 0
|
||||
// and INT32_MAX. Any other value will cause the timer to fire immediately.
|
||||
// We emulate this behavior.
|
||||
const now = OriginalDateNow();
|
||||
const now = DateNow();
|
||||
if (delay > TIMEOUT_MAX) {
|
||||
console.warn(
|
||||
`${delay} does not fit into` +
|
||||
|
@ -497,7 +514,7 @@
|
|||
);
|
||||
delay = 1;
|
||||
}
|
||||
delay = Math.max(0, delay | 0);
|
||||
delay = MathMax(0, delay | 0);
|
||||
|
||||
// Create a new, unscheduled timer object.
|
||||
const timer = {
|
||||
|
@ -510,7 +527,7 @@
|
|||
scheduled: false,
|
||||
};
|
||||
// Register the timer's existence in the id-to-timer map.
|
||||
idMap.set(timer.id, timer);
|
||||
MapPrototypeSet(idMap, timer.id, timer);
|
||||
// Schedule the timer in the due table.
|
||||
schedule(timer, now);
|
||||
return timer.id;
|
||||
|
@ -538,14 +555,14 @@
|
|||
|
||||
function clearTimer(id) {
|
||||
id >>>= 0;
|
||||
const timer = idMap.get(id);
|
||||
const timer = MapPrototypeGet(idMap, id);
|
||||
if (timer === undefined) {
|
||||
// Timer doesn't exist any more or never existed. This is not an error.
|
||||
return;
|
||||
}
|
||||
// Unschedule the timer if it is currently scheduled, and forget about it.
|
||||
unschedule(timer);
|
||||
idMap.delete(timer.id);
|
||||
MapPrototypeDelete(idMap, timer.id);
|
||||
}
|
||||
|
||||
function clearTimeout(id = 0) {
|
||||
|
|
|
@ -2,12 +2,25 @@
|
|||
"use strict";
|
||||
|
||||
((window) => {
|
||||
const {
|
||||
ArrayPrototypeFilter,
|
||||
ArrayPrototypeFind,
|
||||
ArrayPrototypePush,
|
||||
ArrayPrototypeReverse,
|
||||
ArrayPrototypeSlice,
|
||||
ObjectKeys,
|
||||
Symbol,
|
||||
SymbolFor,
|
||||
SymbolToStringTag,
|
||||
TypeError,
|
||||
} = window.__bootstrap.primordials;
|
||||
|
||||
const { webidl, structuredClone } = window.__bootstrap;
|
||||
const { opNow } = window.__bootstrap.timers;
|
||||
const { DOMException } = window.__bootstrap.domException;
|
||||
|
||||
const illegalConstructorKey = Symbol("illegalConstructorKey");
|
||||
const customInspect = Symbol.for("Deno.customInspect");
|
||||
const customInspect = SymbolFor("Deno.customInspect");
|
||||
let performanceEntries = [];
|
||||
|
||||
webidl.converters["PerformanceMarkOptions"] = webidl
|
||||
|
@ -66,10 +79,10 @@
|
|||
name,
|
||||
type,
|
||||
) {
|
||||
return performanceEntries
|
||||
.slice()
|
||||
.reverse()
|
||||
.find((entry) => entry.name === name && entry.entryType === type);
|
||||
return ArrayPrototypeFind(
|
||||
ArrayPrototypeReverse(ArrayPrototypeSlice(performanceEntries)),
|
||||
(entry) => entry.name === name && entry.entryType === type,
|
||||
);
|
||||
}
|
||||
|
||||
function convertMarkToTimestamp(mark) {
|
||||
|
@ -93,7 +106,8 @@
|
|||
name,
|
||||
type,
|
||||
) {
|
||||
return performanceEntries.filter(
|
||||
return ArrayPrototypeFilter(
|
||||
performanceEntries,
|
||||
(entry) =>
|
||||
(name ? entry.name === name : true) &&
|
||||
(type ? entry.entryType === type : true),
|
||||
|
@ -168,7 +182,7 @@
|
|||
|
||||
const _detail = Symbol("[[detail]]");
|
||||
class PerformanceMark extends PerformanceEntry {
|
||||
[Symbol.toStringTag] = "PerformanceMark";
|
||||
[SymbolToStringTag] = "PerformanceMark";
|
||||
|
||||
[_detail] = null;
|
||||
|
||||
|
@ -227,7 +241,7 @@
|
|||
webidl.configurePrototype(PerformanceMark);
|
||||
|
||||
class PerformanceMeasure extends PerformanceEntry {
|
||||
[Symbol.toStringTag] = "PerformanceMeasure";
|
||||
[SymbolToStringTag] = "PerformanceMeasure";
|
||||
|
||||
[_detail] = null;
|
||||
|
||||
|
@ -287,11 +301,13 @@
|
|||
context: "Argument 1",
|
||||
});
|
||||
|
||||
performanceEntries = performanceEntries.filter(
|
||||
performanceEntries = ArrayPrototypeFilter(
|
||||
performanceEntries,
|
||||
(entry) => !(entry.name === markName && entry.entryType === "mark"),
|
||||
);
|
||||
} else {
|
||||
performanceEntries = performanceEntries.filter(
|
||||
performanceEntries = ArrayPrototypeFilter(
|
||||
performanceEntries,
|
||||
(entry) => entry.entryType !== "mark",
|
||||
);
|
||||
}
|
||||
|
@ -305,12 +321,14 @@
|
|||
context: "Argument 1",
|
||||
});
|
||||
|
||||
performanceEntries = performanceEntries.filter(
|
||||
performanceEntries = ArrayPrototypeFilter(
|
||||
performanceEntries,
|
||||
(entry) =>
|
||||
!(entry.name === measureName && entry.entryType === "measure"),
|
||||
);
|
||||
} else {
|
||||
performanceEntries = performanceEntries.filter(
|
||||
performanceEntries = ArrayPrototypeFilter(
|
||||
performanceEntries,
|
||||
(entry) => entry.entryType !== "measure",
|
||||
);
|
||||
}
|
||||
|
@ -380,7 +398,7 @@
|
|||
// throw a SyntaxError. - not implemented
|
||||
const entry = new PerformanceMark(markName, markOptions);
|
||||
// 3.1.1.7 Queue entry - not implemented
|
||||
performanceEntries.push(entry);
|
||||
ArrayPrototypePush(performanceEntries, entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
@ -413,7 +431,7 @@
|
|||
|
||||
if (
|
||||
startOrMeasureOptions && typeof startOrMeasureOptions === "object" &&
|
||||
Object.keys(startOrMeasureOptions).length > 0
|
||||
ObjectKeys(startOrMeasureOptions).length > 0
|
||||
) {
|
||||
if (endMark) {
|
||||
throw new TypeError("Options cannot be passed with endMark.");
|
||||
|
@ -483,7 +501,7 @@
|
|||
: null,
|
||||
illegalConstructorKey,
|
||||
);
|
||||
performanceEntries.push(entry);
|
||||
ArrayPrototypePush(performanceEntries, entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
@ -501,7 +519,7 @@
|
|||
return `${this.constructor.name} ${inspect(this.toJSON())}`;
|
||||
}
|
||||
|
||||
get [Symbol.toStringTag]() {
|
||||
get [SymbolToStringTag]() {
|
||||
return "Performance";
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue