我可以在Nodejs中写一个真正的asynchronouscallback吗?

这是读取文件的一个正常示例:

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 

而这是我自己的callback版本,我希望它可以像上面的文件阅读代码asynchronous,但它不是:

 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的callbackasynchronouscallback,而我的不是呢?

 var f = function(cb) { cb(); }; 

不是asynchronous的,因为它立即调用cb

我想你想要

 var f = function(cb) { setImmediate(function(){ cb(); }); }; 

在你的例子中,while循环占用了事件循环,因此对console.log('All done.')的函数调用在栈上排队。 当事件循环被解除阻塞时,后续的函数调用将被依次调用。

Sandro Pasquali掌握Node.js的 第2章中 ,他讨论了延迟执行和事件循环,以避免事件循环处理和阻塞执行的问题。 为了更好地理解这种非直观的Node.js工作方式,我build议阅读这一章。

掌握Node.js

节点使用单个线程处理JavaScript指令。 在您的JavaScript程序中,没有两个操作会在同一时刻执行,可能会发生在multithreading环境中。 理解这个事实对于理解节点程序或过程如何devise和运行至关重要。

使用setImmediate()可以解决这个问题。

您可以使用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.'); 

setImmediate的文档解释了process.nextTicksetImmediate之间的区别:

中间体以创build的顺序排队,并在每次循环迭代时从队列中popup。 这与process.nextTick不同,后者将执行每个迭代的process.maxTickDepth排队callback。 setImmediate在触发排队的callback之后将产生到事件循环,以确保I / O不被饿死。 当订单被保留执行时,其他I / O事件可能在任何两个计划立即callback之间触发。

编辑:根据@ generalhenry的评论更新答案。