我可以在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.nextTick
和setImmediate
之间的区别:
中间体以创build的顺序排队,并在每次循环迭代时从队列中popup。 这与
process.nextTick
不同,后者将执行每个迭代的process.maxTickDepth
排队callback。setImmediate
在触发排队的callback之后将产生到事件循环,以确保I / O不被饿死。 当订单被保留执行时,其他I / O事件可能在任何两个计划立即callback之间触发。
编辑:根据@ generalhenry的评论更新答案。