这是读取文件的正常示例:
var fs = require('fs');
fs.readFile('./gparted-live-0.18.0-2-i486.iso', function (err, data) {
console.log(data.length);
});
console.log('All done.');
上面的代码输出:
All done.
187695104
虽然这是我自己的回调版本,但我希望它可以像上面的文件读取代码那样异步,但它不是:
var f = function(cb) {
cb();
};
f(function() {
var i = 0;
// Do some very long job.
while(++i < (1<<30)) {}
console.log('Cb comes back.')
});
console.log('All done.');
上面的代码输出:
Cb comes back.
All done.
到目前为止,很清楚,在文件读取代码的第一个版本中,All done.
始终在读取文件之前打印。但是,在第二个我自制的代码版本中,All done.
始终等待very long job
完成。
那么究竟是什么让fs.readFile
的回调成为异步回叫而不是我的呢?
答案 0 :(得分:3)
var f = function(cb) {
cb();
};
不是异步,因为它会立即调用cb
。
我想你想要
var f = function(cb) {
setImmediate(function(){ cb(); });
};
答案 1 :(得分:3)
在您的示例中,while循环占用事件循环,因此对console.log('All done.')
的函数调用在堆栈上排队。当事件循环被解除阻塞时,将按顺序调用后续函数调用。
在Sandro Pasquali的 掌握Node.js - 第2章中,他讨论了延迟执行和事件循环,以避免事件循环的问题持有并阻止执行。我建议阅读该章,以便更好地理解在Node.js中使用这种非直观的工作方式。
来自 掌握Node.js ...
Node使用单个线程处理JavaScript指令。内 你的JavaScript程序没有两个操作可以完全执行 同一时刻,就像多线程环境中可能发生的那样。 理解这一事实对于理解Node是如何必不可少的 程序或过程的设计和运行。
使用setImmediate()
可以解决此问题。
答案 2 :(得分:2)
你可以使用setImmediate()
推迟代码的执行,直到事件循环的下一个循环,我认为它可以实现你想要的东西:
var f = function(cb) {
cb();
};
f(function() {
setImmediate(function() {
var i = 0;
// Do some very long job.
while(++i < (1<<30)) {}
console.log('Cb comes back.')
});
});
console.log('All done.');
The documentation for setImmediate
解释了process.nextTick
和setImmediate
之间的区别:
Immediates按创建的顺序排队,并在每次循环迭代时从队列中弹出一次。这与
process.nextTick
不同,后者将在每次迭代中执行process.maxTickDepth
个排队回调。setImmediate
将在触发排队回调后生成事件循环,以确保I / O不会被饿死。虽然保留了订单以便执行,但其他I / O事件可能会在任何两个预定的立即回调之间触发。
编辑:根据@ generalhenry的评论更新答案。