11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst {
41cb0ef41Sopenharmony_ci  Array,
51cb0ef41Sopenharmony_ci  FunctionPrototypeBind,
61cb0ef41Sopenharmony_ci} = primordials;
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ciconst {
91cb0ef41Sopenharmony_ci  // For easy access to the nextTick state in the C++ land,
101cb0ef41Sopenharmony_ci  // and to avoid unnecessary calls into JS land.
111cb0ef41Sopenharmony_ci  tickInfo,
121cb0ef41Sopenharmony_ci  // Used to run V8's micro task queue.
131cb0ef41Sopenharmony_ci  runMicrotasks,
141cb0ef41Sopenharmony_ci  setTickCallback,
151cb0ef41Sopenharmony_ci  enqueueMicrotask,
161cb0ef41Sopenharmony_ci} = internalBinding('task_queue');
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ciconst {
191cb0ef41Sopenharmony_ci  setHasRejectionToWarn,
201cb0ef41Sopenharmony_ci  hasRejectionToWarn,
211cb0ef41Sopenharmony_ci  listenForRejections,
221cb0ef41Sopenharmony_ci  processPromiseRejections,
231cb0ef41Sopenharmony_ci} = require('internal/process/promises');
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ciconst {
261cb0ef41Sopenharmony_ci  getDefaultTriggerAsyncId,
271cb0ef41Sopenharmony_ci  newAsyncId,
281cb0ef41Sopenharmony_ci  initHooksExist,
291cb0ef41Sopenharmony_ci  destroyHooksExist,
301cb0ef41Sopenharmony_ci  emitInit,
311cb0ef41Sopenharmony_ci  emitBefore,
321cb0ef41Sopenharmony_ci  emitAfter,
331cb0ef41Sopenharmony_ci  emitDestroy,
341cb0ef41Sopenharmony_ci  symbols: { async_id_symbol, trigger_async_id_symbol },
351cb0ef41Sopenharmony_ci} = require('internal/async_hooks');
361cb0ef41Sopenharmony_ciconst FixedQueue = require('internal/fixed_queue');
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ciconst {
391cb0ef41Sopenharmony_ci  validateFunction,
401cb0ef41Sopenharmony_ci} = require('internal/validators');
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ciconst { AsyncResource } = require('async_hooks');
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci// *Must* match Environment::TickInfo::Fields in src/env.h.
451cb0ef41Sopenharmony_ciconst kHasTickScheduled = 0;
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_cifunction hasTickScheduled() {
481cb0ef41Sopenharmony_ci  return tickInfo[kHasTickScheduled] === 1;
491cb0ef41Sopenharmony_ci}
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_cifunction setHasTickScheduled(value) {
521cb0ef41Sopenharmony_ci  tickInfo[kHasTickScheduled] = value ? 1 : 0;
531cb0ef41Sopenharmony_ci}
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ciconst queue = new FixedQueue();
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci// Should be in sync with RunNextTicksNative in node_task_queue.cc
581cb0ef41Sopenharmony_cifunction runNextTicks() {
591cb0ef41Sopenharmony_ci  if (!hasTickScheduled() && !hasRejectionToWarn())
601cb0ef41Sopenharmony_ci    runMicrotasks();
611cb0ef41Sopenharmony_ci  if (!hasTickScheduled() && !hasRejectionToWarn())
621cb0ef41Sopenharmony_ci    return;
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci  processTicksAndRejections();
651cb0ef41Sopenharmony_ci}
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_cifunction processTicksAndRejections() {
681cb0ef41Sopenharmony_ci  let tock;
691cb0ef41Sopenharmony_ci  do {
701cb0ef41Sopenharmony_ci    while ((tock = queue.shift()) !== null) {
711cb0ef41Sopenharmony_ci      const asyncId = tock[async_id_symbol];
721cb0ef41Sopenharmony_ci      emitBefore(asyncId, tock[trigger_async_id_symbol], tock);
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci      try {
751cb0ef41Sopenharmony_ci        const callback = tock.callback;
761cb0ef41Sopenharmony_ci        if (tock.args === undefined) {
771cb0ef41Sopenharmony_ci          callback();
781cb0ef41Sopenharmony_ci        } else {
791cb0ef41Sopenharmony_ci          const args = tock.args;
801cb0ef41Sopenharmony_ci          switch (args.length) {
811cb0ef41Sopenharmony_ci            case 1: callback(args[0]); break;
821cb0ef41Sopenharmony_ci            case 2: callback(args[0], args[1]); break;
831cb0ef41Sopenharmony_ci            case 3: callback(args[0], args[1], args[2]); break;
841cb0ef41Sopenharmony_ci            case 4: callback(args[0], args[1], args[2], args[3]); break;
851cb0ef41Sopenharmony_ci            default: callback(...args);
861cb0ef41Sopenharmony_ci          }
871cb0ef41Sopenharmony_ci        }
881cb0ef41Sopenharmony_ci      } finally {
891cb0ef41Sopenharmony_ci        if (destroyHooksExist())
901cb0ef41Sopenharmony_ci          emitDestroy(asyncId);
911cb0ef41Sopenharmony_ci      }
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci      emitAfter(asyncId);
941cb0ef41Sopenharmony_ci    }
951cb0ef41Sopenharmony_ci    runMicrotasks();
961cb0ef41Sopenharmony_ci  } while (!queue.isEmpty() || processPromiseRejections());
971cb0ef41Sopenharmony_ci  setHasTickScheduled(false);
981cb0ef41Sopenharmony_ci  setHasRejectionToWarn(false);
991cb0ef41Sopenharmony_ci}
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci// `nextTick()` will not enqueue any callback when the process is about to
1021cb0ef41Sopenharmony_ci// exit since the callback would not have a chance to be executed.
1031cb0ef41Sopenharmony_cifunction nextTick(callback) {
1041cb0ef41Sopenharmony_ci  validateFunction(callback, 'callback');
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci  if (process._exiting)
1071cb0ef41Sopenharmony_ci    return;
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ci  let args;
1101cb0ef41Sopenharmony_ci  switch (arguments.length) {
1111cb0ef41Sopenharmony_ci    case 1: break;
1121cb0ef41Sopenharmony_ci    case 2: args = [arguments[1]]; break;
1131cb0ef41Sopenharmony_ci    case 3: args = [arguments[1], arguments[2]]; break;
1141cb0ef41Sopenharmony_ci    case 4: args = [arguments[1], arguments[2], arguments[3]]; break;
1151cb0ef41Sopenharmony_ci    default:
1161cb0ef41Sopenharmony_ci      args = new Array(arguments.length - 1);
1171cb0ef41Sopenharmony_ci      for (let i = 1; i < arguments.length; i++)
1181cb0ef41Sopenharmony_ci        args[i - 1] = arguments[i];
1191cb0ef41Sopenharmony_ci  }
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ci  if (queue.isEmpty())
1221cb0ef41Sopenharmony_ci    setHasTickScheduled(true);
1231cb0ef41Sopenharmony_ci  const asyncId = newAsyncId();
1241cb0ef41Sopenharmony_ci  const triggerAsyncId = getDefaultTriggerAsyncId();
1251cb0ef41Sopenharmony_ci  const tickObject = {
1261cb0ef41Sopenharmony_ci    [async_id_symbol]: asyncId,
1271cb0ef41Sopenharmony_ci    [trigger_async_id_symbol]: triggerAsyncId,
1281cb0ef41Sopenharmony_ci    callback,
1291cb0ef41Sopenharmony_ci    args,
1301cb0ef41Sopenharmony_ci  };
1311cb0ef41Sopenharmony_ci  if (initHooksExist())
1321cb0ef41Sopenharmony_ci    emitInit(asyncId, 'TickObject', triggerAsyncId, tickObject);
1331cb0ef41Sopenharmony_ci  queue.push(tickObject);
1341cb0ef41Sopenharmony_ci}
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_cifunction runMicrotask() {
1371cb0ef41Sopenharmony_ci  this.runInAsyncScope(() => {
1381cb0ef41Sopenharmony_ci    const callback = this.callback;
1391cb0ef41Sopenharmony_ci    try {
1401cb0ef41Sopenharmony_ci      callback();
1411cb0ef41Sopenharmony_ci    } finally {
1421cb0ef41Sopenharmony_ci      this.emitDestroy();
1431cb0ef41Sopenharmony_ci    }
1441cb0ef41Sopenharmony_ci  });
1451cb0ef41Sopenharmony_ci}
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ciconst defaultMicrotaskResourceOpts = { requireManualDestroy: true };
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_cifunction queueMicrotask(callback) {
1501cb0ef41Sopenharmony_ci  validateFunction(callback, 'callback');
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_ci  const asyncResource = new AsyncResource(
1531cb0ef41Sopenharmony_ci    'Microtask',
1541cb0ef41Sopenharmony_ci    defaultMicrotaskResourceOpts,
1551cb0ef41Sopenharmony_ci  );
1561cb0ef41Sopenharmony_ci  asyncResource.callback = callback;
1571cb0ef41Sopenharmony_ci
1581cb0ef41Sopenharmony_ci  enqueueMicrotask(FunctionPrototypeBind(runMicrotask, asyncResource));
1591cb0ef41Sopenharmony_ci}
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_cimodule.exports = {
1621cb0ef41Sopenharmony_ci  setupTaskQueue() {
1631cb0ef41Sopenharmony_ci    // Sets the per-isolate promise rejection callback
1641cb0ef41Sopenharmony_ci    listenForRejections();
1651cb0ef41Sopenharmony_ci    // Sets the callback to be run in every tick.
1661cb0ef41Sopenharmony_ci    setTickCallback(processTicksAndRejections);
1671cb0ef41Sopenharmony_ci    return {
1681cb0ef41Sopenharmony_ci      nextTick,
1691cb0ef41Sopenharmony_ci      runNextTicks,
1701cb0ef41Sopenharmony_ci    };
1711cb0ef41Sopenharmony_ci  },
1721cb0ef41Sopenharmony_ci  queueMicrotask,
1731cb0ef41Sopenharmony_ci};
174