process.nextTick(callback[, ...args])


  • callback <Function>
  • ...args <any> 当调用 callback 时传入的额外参数。

process.nextTick() 会添加 callback 到下一个时间点队列。 在 JavaScript 堆栈上的当前操作运行完成之后,且允许事件循环继续之前,此队列会被完全耗尽。 如果递归地调用 process.nextTick(),则可以创建无限的循环。 有关更多背景信息,请参见事件循环指南。

console.log('开始');
process.nextTick(() => {
  console.log('下一个时间点的回调');
});
console.log('调度');
// 输出:
// 开始
// 调度
// 下一个时间点的回调

这在开发 API 时非常重要,可以在构造对象之后但在发生任何 I/O 之前,为用户提供分配事件句柄的机会:

function MyThing(options) {
  this.setupOptions(options);

  process.nextTick(() => {
    this.startDoingStuff();
  });
}

const thing = new MyThing();
thing.getReadyForStuff();

// thing.startDoingStuff() 现在(而不是在之前)会被调用。

对于 100% 同步或 100% 异步的 API,此方法也非常重要。 参考以下示例:

// 警告!不要这样使用!这是不安全的!
function maybeSync(arg, cb) {
  if (arg) {
    cb();
    return;
  }

  fs.stat('file', cb);
}

此 API 是不安全的,因为在以下情况中:

const maybeTrue = Math.random() > 0.5;

maybeSync(maybeTrue, () => {
  foo();
});

bar();

不清楚 foo()bar() 哪个会先被调用。

以下方法则更好:

function definitelyAsync(arg, cb) {
  if (arg) {
    process.nextTick(cb);
    return;
  }

  fs.stat('file', cb);
}
  • callback <Function>
  • ...args <any> Additional arguments to pass when invoking the callback

process.nextTick() adds callback to the "next tick queue". This queue is fully drained after the current operation on the JavaScript stack runs to completion and before the event loop is allowed to continue. It's possible to create an infinite loop if one were to recursively call process.nextTick(). See the Event Loop guide for more background.

console.log('start');
process.nextTick(() => {
  console.log('nextTick callback');
});
console.log('scheduled');
// Output:
// start
// scheduled
// nextTick callback

This is important when developing APIs in order to give users the opportunity to assign event handlers after an object has been constructed but before any I/O has occurred:

function MyThing(options) {
  this.setupOptions(options);

  process.nextTick(() => {
    this.startDoingStuff();
  });
}

const thing = new MyThing();
thing.getReadyForStuff();

// thing.startDoingStuff() gets called now, not before.

It is very important for APIs to be either 100% synchronous or 100% asynchronous. Consider this example:

// WARNING!  DO NOT USE!  BAD UNSAFE HAZARD!
function maybeSync(arg, cb) {
  if (arg) {
    cb();
    return;
  }

  fs.stat('file', cb);
}

This API is hazardous because in the following case:

const maybeTrue = Math.random() > 0.5;

maybeSync(maybeTrue, () => {
  foo();
});

bar();

It is not clear whether foo() or bar() will be called first.

The following approach is much better:

function definitelyAsync(arg, cb) {
  if (arg) {
    process.nextTick(cb);
    return;
  }

  fs.stat('file', cb);
}