Node.js:具有分支的串行操作

时间:2015-09-21 18:11:49

标签: node.js

我是node.js的新手,并将其用于从syslog消息中获取数据并将其存储到数据库的后端。

我遇到了以下类型的串行操作:

1. Query the database

2. If the query value is X do A. otherwise do B.
    A. 1. Store "this" in DB
       2. Query the database again
       3. If the query value is Y do P. otherwise do Q.
           P. Store "something"
           Q. Store "something else"

    B. 1. Store "that" in the DB
       2. Store "the other thing" in the DB

这里的要点是我有一些操作需要按顺序进行,但顺序中有分支逻辑。

我最终陷入了回调地狱(当我来到Node时,我不知道那是什么......我现在这样做)。

我已将async库用于更直接的事情 - 例如按async.forEachOfSeriesasync.queue执行操作。但我不认为如果事情必须按顺序发生但有分支就有办法使用它。

有没有办法处理这个不会导致回调的地狱?

1 个答案:

答案 0 :(得分:3)

这样的任何类型的复杂逻辑实际上都会从每个异步操作使用promise中受益,特别是当你处理错误时,也只是为了构造逻辑流程。

由于您还没有提供任何实际代码,我将举一个例子。假设您有两个核心异步操作,它们都返回一个承诺:query(...)store(...)

然后,您可以像这样实现上述逻辑:

query(...).then(function(value) {
    if (value === X) {
        return store(value).then(function() {
            return query(...).then(function(newValue) {
               if (newValue === Y) {
                   return store("something");
               } else {
                   return store("something else");
               }
            })
        });
    } else {
        return store("that").then(function() {
            return store("the other thing");
        });
    }
}).then(function() {
    // everything succeeded here
}, function(err) {
    // error occurred in anyone of the async operations
});

我不会假装这很简单。无论你如何操作,在七种不同的异步操作中实现逻辑流程只是一些代码。但是,承诺可以减少其他方面的痛苦,并且更容易进行强大的错误处理工作,并将其与其他异步操作联系起来。

这里使用的承诺的主要关键是:

  1. 让所有异步操作返回以值解析的promises或以失败为原因拒绝。
  2. 然后,您可以将.then()处理程序附加到任何承诺,以查看异步操作何时成功完成或出错。
  3. .then()的第一个回调是成功处理程序,第二个回调是错误处理程序。
  4. 如果您从.then()处理程序中返回一个承诺,那么该承诺将被链接到#34;到前一个,所以所有成功和错误状态都被链接并返回到原始的promise状态。这就是为什么你看到上面的代码总是返回嵌套的promises。这样可以自动将错误返回给调用者,并允许您将值一直返回给调用者,即使是深层嵌套的promise也是如此。
  5. 如果上述代码中的任何承诺拒绝,那么它将停止该承诺链,直到找到实际的拒绝处理程序并将该错误传播回该拒绝处理程序。由于上面代码中唯一的拒绝处理程序位于to级别,因此可以捕获并查看所有错误,无论它发生的嵌套异步混乱有多深(尝试使用普通回调可靠地执行此操作 - 它是' s很难)。
  6. 原生承诺

    Node.js已经内置了承诺,因此您可以使用本机承诺。但是,node.js实现的promise规范并不是特别丰富,因此很多人使用promise库(我使用Bluebird进行所有node.js开发)来获得其他功能。其中一个更突出的特点是能够实现" promisify"现有的非承诺API。这允许您获取仅适用于回调的函数,并创建一个通过promise工作的新函数。我发现这特别有用,因为许多已经存在一段时间的API本身并不会返回承诺。

    宣传非承诺界面

    假设您有一个使用传统回调的异步操作,并且您希望"宣传它"。以下是您可以手动执行此操作的示例。假设你有db.query(whatToSearchFor, callback)。您可以像这样手动宣传:

    function queryAsync(whatToSearchFor) {
        return new Promise(function(resolve, reject) {
            db.query(whatToSearchFor, function(err, data) {
               if (!err) {
                   reject(err);
               } else {
                   resolve(data);
               }
            });
        });
    }
    

    然后,您只需致电queryAsync(whatToSearchFor)并使用返回的承诺。

    queryAsync("foo").then(function(data) {
        // data here
    }, function(err) {
        // error here
    });
    

    或者,如果你使用类似Bluebird promise library的东西,它有一个函数用于宣传任何异步函数,它通过作为最后一个参数传递的node.js样式回调来传递其结果:

    var queryAsync = Promise.promisify(db.query, db);