1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-30 16:40:57 -05:00
denoland-deno/ext/node/polyfills/_next_tick.ts
2024-01-10 15:37:25 -07:00

153 lines
4.4 KiB
TypeScript

// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// Copyright Joyent, Inc. and other Node contributors.
// TODO(petamoriken): enable prefer-primordials for node polyfills
// deno-lint-ignore-file prefer-primordials
import { core } from "ext:core/mod.js";
import { validateFunction } from "ext:deno_node/internal/validators.mjs";
import { _exiting } from "ext:deno_node/_process/exiting.ts";
import { FixedQueue } from "ext:deno_node/internal/fixed_queue.ts";
interface Tock {
callback: (...args: Array<unknown>) => void;
args: Array<unknown>;
}
let nextTickEnabled = false;
export function enableNextTick() {
nextTickEnabled = true;
}
const queue = new FixedQueue();
export function processTicksAndRejections() {
let tock;
do {
// deno-lint-ignore no-cond-assign
while (tock = queue.shift()) {
// FIXME(bartlomieju): Deno currently doesn't support async hooks
// const asyncId = tock[async_id_symbol];
// emitBefore(asyncId, tock[trigger_async_id_symbol], tock);
try {
const callback = (tock as Tock).callback;
if ((tock as Tock).args === undefined) {
callback();
} else {
const args = (tock as Tock).args;
switch (args.length) {
case 1:
callback(args[0]);
break;
case 2:
callback(args[0], args[1]);
break;
case 3:
callback(args[0], args[1], args[2]);
break;
case 4:
callback(args[0], args[1], args[2], args[3]);
break;
default:
callback(...args);
}
}
} finally {
// FIXME(bartlomieju): Deno currently doesn't support async hooks
// if (destroyHooksExist())
// emitDestroy(asyncId);
}
// FIXME(bartlomieju): Deno currently doesn't support async hooks
// emitAfter(asyncId);
}
core.runMicrotasks();
// FIXME(bartlomieju): Deno currently doesn't unhandled rejections
// } while (!queue.isEmpty() || processPromiseRejections());
} while (!queue.isEmpty());
core.setHasTickScheduled(false);
// FIXME(bartlomieju): Deno currently doesn't unhandled rejections
// setHasRejectionToWarn(false);
}
export function runNextTicks() {
// FIXME(bartlomieju): Deno currently doesn't unhandled rejections
// if (!hasTickScheduled() && !hasRejectionToWarn())
// runMicrotasks();
// if (!hasTickScheduled() && !hasRejectionToWarn())
// return;
if (!core.hasTickScheduled()) {
core.runMicrotasks();
return true;
}
processTicksAndRejections();
return true;
}
// `nextTick()` will not enqueue any callback when the process is about to
// exit since the callback would not have a chance to be executed.
export function nextTick(this: unknown, callback: () => void): void;
export function nextTick<T extends Array<unknown>>(
this: unknown,
callback: (...args: T) => void,
...args: T
): void;
export function nextTick<T extends Array<unknown>>(
this: unknown,
callback: (...args: T) => void,
...args: T
) {
// If we're snapshotting we don't want to push nextTick to be run. We'll
// enable next ticks in "__bootstrapNodeProcess()";
if (!nextTickEnabled) {
return;
}
validateFunction(callback, "callback");
if (_exiting) {
return;
}
// TODO(bartlomieju): seems superfluous if we don't depend on `arguments`
let args_;
switch (args.length) {
case 0:
break;
case 1:
args_ = [args[0]];
break;
case 2:
args_ = [args[0], args[1]];
break;
case 3:
args_ = [args[0], args[1], args[2]];
break;
default:
args_ = new Array(args.length);
for (let i = 0; i < args.length; i++) {
args_[i] = args[i];
}
}
if (queue.isEmpty()) {
core.setHasTickScheduled(true);
}
// FIXME(bartlomieju): Deno currently doesn't support async hooks
// const asyncId = newAsyncId();
// const triggerAsyncId = getDefaultTriggerAsyncId();
const tickObject = {
// FIXME(bartlomieju): Deno currently doesn't support async hooks
// [async_id_symbol]: asyncId,
// [trigger_async_id_symbol]: triggerAsyncId,
callback,
args: args_,
};
// FIXME(bartlomieju): Deno currently doesn't support async hooks
// if (initHooksExist())
// emitInit(asyncId, 'TickObject', triggerAsyncId, tickObject);
queue.push(tickObject);
}