一尘不染

在Node.js中等待多个回调的惯用方式

node.js

假设您需要执行一些依赖于某些临时文件的操作。既然我们在这里谈论Node,那么这些操作显然是异步的。为了知道何时可以删除临时文件,等待所有操作完成的惯用方式是什么?

这是一些代码,显示我想做什么:

do_something(tmp_file_name, function(err) {});
do_something_other(tmp_file_name, function(err) {});
fs.unlink(tmp_file_name);

但是,如果我这样编写,则可以在前两个调用有机会使用该文件之前执行第三个调用。我需要某种方法来确保前两个调用在结束之前已经完成(调用了它们的回调),而没有嵌套这些调用(并使它们在实践中保持同步)。

我考虑过在回调上使用事件发射器,并将计数器注册为接收器。计数器将接收已完成的事件并计算仍有多少操作待处理。当最后一个完成时,它将删除该文件。但是存在比赛条件的风险,我不确定这通常是如何完成的。

Node人员如何解决此类问题?


阅读 302

收藏
2020-07-07

共1个答案

一尘不染

更新:

现在,我建议看一下:

Promise对象用于延迟和异步计算。Promise表示尚未完成的操作,但有望在将来进行。

一个流行的承诺库是蓝鸟。A建议看看为什么答应

您应该使用promise来解决这个问题:

>     >     fs.readFile("file.json", function (err, val) {
>         if (err) {
>             console.error("unable to read file");
>         }
>         else {
>             try {
>                 val = JSON.parse(val);
>                 console.log(val.success);
>             }
>             catch (e) {
>                 console.error("invalid json in file");
>             }
>         }
>     });

变成这个:

>     >     fs.readFileAsync("file.json").then(JSON.parse).then(function (val)
> {
>         console.log(val.success);
>     })
>     .catch(SyntaxError, function (e) {
>         console.error("invalid json in file");
>     })
>     .catch(function (e) {
>         console.error("unable to read file");
>     });
  • 生成器: 例如,通过co

使用Promise,基于Node.js和浏览器的基于生成器的控制流优势,可让您以一种不错的方式编写非阻塞代码。

>     >     var co = require('co');
>  
>     co(function *(){
>       // yield any promise
>       var result = yield Promise.resolve(true);
>     }).catch(onerror);
>  
>     co(function *(){
>       // resolve multiple promises in parallel
>       var a = Promise.resolve(1);
>       var b = Promise.resolve(2);
>       var c = Promise.resolve(3);
>       var res = yield [a, b, c];
>       console.log(res);
>       // => [1, 2, 3]
>     }).catch(onerror);
>  
>     // errors can be try/catched
>     co(function *(){
>       try {
>         yield Promise.reject(new Error('boom'));
>       } catch (err) {
>         console.error(err.message); // "boom"
>      }
>     }).catch(onerror);
>  
>     function onerror(err) {
>       // log any uncaught errors
>       // co will not throw any errors you do not handle!!!
>       // HANDLE ALL YOUR ERRORS!!!
>       console.error(err.stack);
>     }

如果我理解正确,我想您应该看一下非常好的异步库。您应该特别看一下该系列。只是来自github页面的摘录的一个副本:

    async.series([
        function(callback){
            // do some stuff ...
            callback(null, 'one');
        },
        function(callback){
            // do some more stuff ...
            callback(null, 'two');
        },
    ],
    // optional callback
    function(err, results){
        // results is now equal to ['one', 'two']
    });


    // an example using an object instead of an array
    async.series({
        one: function(callback){
            setTimeout(function(){
                callback(null, 1);
            }, 200);
        },
        two: function(callback){
            setTimeout(function(){
                callback(null, 2);
            }, 100);
        },
    },
    function(err, results) {
        // results is now equals to: {one: 1, two: 2}
    });

另外,该库还可以在浏览器中运行。

2020-07-07