我可以在Nodejs中编写一个真正的异步回调吗?

时间:2014-06-23 20:22:11

标签: node.js asynchronous

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

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的回调成为异步回叫而不是我的呢?

3 个答案:

答案 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.nextTicksetImmediate之间的区别:

  

Immediates按创建的顺序排队,并在每次循环迭代时从队列中弹出一次。这与process.nextTick不同,后者将在每次迭代中执行process.maxTickDepth个排队回调。 setImmediate将在触发排队回调后生成事件循环,以确保I / O不会被饿死。虽然保留了订单以便执行,但其他I / O事件可能会在任何两个预定的立即回调之间触发。

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