setImmediate, setTimeout, process.nextTick 的奇怪问题
发布于 5 年前 作者 gvforjob 3694 次浏览 最后一次编辑是 3 年前 来自 问答
process.nextTick(function() {
	console.log('nextTick 1');
});
process.nextTick(function() {
	console.log('nextTick 2');
});
setImmediate(function() {
	console.log('setImmediate 1');
	process.nextTick(function() {
		console.log('nextTick powerful');
	});
});
setImmediate(function() {
	console.log('setImmediate 2');
});
setTimeout(function() {
	console.log('timeout');
}, 0);
console.log('console');

按照朴大神的说法,nextTick 是保存在数组里,一次执行所有(没超出那个最大限制),setImmediate 是保存在链表,一次执行一个 官方文档也有描述:To schedule the “immediate” execution of callback after I/O events callbacks and before setTimeout and setInterval . 所以感觉上应该是这样: console nextTick 1 nextTick 2 setImmediate 1 nextTick powerful setImmediate 2 timeout

node 为 v0.12.0这么执行的结果是这样的: console nextTick 1 nextTick 2 timeout setImmediate 1 setImmediate 2 nextTick powerful timeout 竟然在最前面,nextTick powerful 竟然在最后面

node 为 v0.10.35这么执行的结果是这样的: console nextTick 1 nextTick 2 timeout setImmediate 1 nextTick powerful setImmediate 2 那个timeout还是不太符合预期。。。。

这,是我理解错了 ,还是node的机制更改了文档没告诉我么?

6 回复

正常来说setImmediate应该在事件循环之后调用callback,两个版本的出入实在不知道为什么,看看issues有没有类似的呢?

我测试的结果与 LZ 一样,确实奇怪。。。

还真是,翻了翻最近的Issues貌似也没人提得样子

我觉得可以让朴大神出来分析科普下~

https://github.com/joyent/node/issues/6034#issuecomment-30019424

687474703a2f2f68746d6c352e6f687473752e6f72672f6e65775f736574496d6d6564696174655f73656d616e746963732e706e67.png

@tjfontaine: "timers are based on a time in the future, even if it’s 0, while check immediate is always on the next turn of the loop. So it’s possible that the delay of the event loop is low enough for the timer to fire after the immediate.

You shouldn’t necessarily be concerned about the order of operations in this regard though in my estimation."

https://github.com/joyent/node/blob/master/lib/timers.js#L200

exports.setTimeout = function(callback, after) {
  var timer;

  after *= 1; // coalesce to number or NaN

  if (!(after >= 1 && after <= TIMEOUT_MAX)) {
	after = 1; // schedule on next tick, follows browser behaviour
  }

  timer = new Timeout(after);

  if (arguments.length <= 2) {
	timer._onTimeout = callback;
  } else {
	/*
	 * Sometimes setTimeout is called with arguments, EG
	 *
	 *   setTimeout(callback, 2000, "hello", "world")
	 *
	 * If that's the case we need to call the callback with
	 * those args. The overhead of an extra closure is not
	 * desired in the normal case.
	 */
	var args = Array.prototype.slice.call(arguments, 2);
	timer._onTimeout = function() {
	  callback.apply(timer, args);
	}
  }

  if (process.domain) timer.domain = process.domain;

  exports.active(timer);

  return timer;
};

@steamwheedle 谢谢,非常感谢~~~

回到顶部