all files / lib/internal/process/ next_tick.js

94.51% Statements 86/91
87.5% Branches 28/32
100% Functions 9/9
94.51% Lines 86/91
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158    1553×   1553× 1553× 1553× 1553× 1553×     1553×     1553× 1553×   1553×   1553× 1553×         1553×   1553×   1553× 31740× 26154× 26154× 26154×           31740×     1553× 76×   72×         72× 72×     1553× 72× 72×   72×   38×     1553× 132519× 10750×   121769×   19784× 19776×   75767× 75749×   689× 689×   25529×             1553× 30832×   30832× 30837× 129278× 129278× 129278×       129278× 129205×     30764× 30764× 30764×       1553× 2009×   2009× 2011× 3241× 3241× 3241× 3241× 3241× 504×       3241× 2206×   2206× 485×   976× 976× 976×       1553× 132730× 132730× 132730×     1553× 132736×   132730×     132730× 132730× 122039× 122039× 276519×     132730× 132730×      
'use strict';
 
exports.setup = setupNextTick;
 
function setupNextTick() {
  const promises = require('internal/process/promises');
  const emitPendingUnhandledRejections = promises.setup(scheduleMicrotasks);
  var nextTickQueue = [];
  var microtasksScheduled = false;
 
  // Used to run V8's micro task queue.
  var _runMicrotasks = {};
 
  // *Must* match Environment::TickInfo::Fields in src/env.h.
  var kIndex = 0;
  var kLength = 1;
 
  process.nextTick = nextTick;
  // Needs to be accessible from beyond this scope.
  process._tickCallback = _tickCallback;
  process._tickDomainCallback = _tickDomainCallback;
 
  // This tickInfo thing is used so that the C++ code in src/node.cc
  // can have easy access to our nextTick state, and avoid unnecessary
  // calls into JS land.
  const tickInfo = process._setupNextTick(_tickCallback, _runMicrotasks);
 
  _runMicrotasks = _runMicrotasks.runMicrotasks;
 
  function tickDone() {
    if (tickInfo[kLength] !== 0) {
      Eif (tickInfo[kLength] <= tickInfo[kIndex]) {
        nextTickQueue = [];
        tickInfo[kLength] = 0;
      } else {
        nextTickQueue.splice(0, tickInfo[kIndex]);
        tickInfo[kLength] = nextTickQueue.length;
      }
    }
    tickInfo[kIndex] = 0;
  }
 
  function scheduleMicrotasks() {
    if (microtasksScheduled)
      return;
 
    nextTickQueue.push({
      callback: runMicrotasksCallback,
      domain: null
    });
 
    tickInfo[kLength]++;
    microtasksScheduled = true;
  }
 
  function runMicrotasksCallback() {
    microtasksScheduled = false;
    _runMicrotasks();
 
    if (tickInfo[kIndex] < tickInfo[kLength] ||
        emitPendingUnhandledRejections())
      scheduleMicrotasks();
  }
 
  function _combinedTickCallback(args, callback) {
    if (args === undefined) {
      callback();
    } else {
      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;
        default:
          callback.apply(null, args);
      }
    }
  }
 
  // Run callbacks that have no domain.
  // Using domains will cause this to be overridden.
  function _tickCallback() {
    var callback, args, tock;
 
    do {
      while (tickInfo[kIndex] < tickInfo[kLength]) {
        tock = nextTickQueue[tickInfo[kIndex]++];
        callback = tock.callback;
        args = tock.args;
        // Using separate callback execution functions allows direct
        // callback invocation with small numbers of arguments to avoid the
        // performance hit associated with using `fn.apply()`
        _combinedTickCallback(args, callback);
        Iif (1e4 < tickInfo[kIndex])
          tickDone();
      }
      tickDone();
      _runMicrotasks();
      emitPendingUnhandledRejections();
    } while (tickInfo[kLength] !== 0);
  }
 
  function _tickDomainCallback() {
    var callback, domain, args, tock;
 
    do {
      while (tickInfo[kIndex] < tickInfo[kLength]) {
        tock = nextTickQueue[tickInfo[kIndex]++];
        callback = tock.callback;
        domain = tock.domain;
        args = tock.args;
        if (domain)
          domain.enter();
        // Using separate callback execution functions allows direct
        // callback invocation with small numbers of arguments to avoid the
        // performance hit associated with using `fn.apply()`
        _combinedTickCallback(args, callback);
        Iif (1e4 < tickInfo[kIndex])
          tickDone();
        if (domain)
          domain.exit();
      }
      tickDone();
      _runMicrotasks();
      emitPendingUnhandledRejections();
    } while (tickInfo[kLength] !== 0);
  }
 
  function TickObject(c, args) {
    this.callback = c;
    this.domain = process.domain || null;
    this.args = args;
  }
 
  function nextTick(callback) {
    if (typeof callback !== 'function')
      throw new TypeError('callback is not a function');
    // on the way out, don't bother. it won't get fired anyway.
    Iif (process._exiting)
      return;
 
    var args;
    if (arguments.length > 1) {
      args = new Array(arguments.length - 1);
      for (var i = 1; i < arguments.length; i++)
        args[i - 1] = arguments[i];
    }
 
    nextTickQueue.push(new TickObject(callback, args));
    tickInfo[kLength]++;
  }
}