如何避免异步函数在 Node 中长时间嵌套.js

我想创建一个显示数据库中某些数据的页面,因此我创建了一些从数据库获取该数据的函数。我只是Node.js的新手,所以据我所知,如果我想在单个页面(HTTP响应)中使用所有这些,我必须将它们全部嵌套:

http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  var html = "<h1>Demo page</h1>";
  getSomeDate(client, function(someData) {
    html += "<p>"+ someData +"</p>";
    getSomeOtherDate(client, function(someOtherData) {
      html += "<p>"+ someOtherData +"</p>";
      getMoreData(client, function(moreData) {
        html += "<p>"+ moreData +"</p>";
        res.write(html);
        res.end();
      });
    });
  });

如果有很多这样的函数,那么嵌套就成了一个问题

有没有办法避免这种情况?我想这与你如何组合多个异步函数有关,这似乎是一些基本的东西。


答案 1

有趣的观察。请注意,在 JavaScript 中,您通常可以将内联匿名回调函数替换为命名函数变量。

以下是:

http.createServer(function (req, res) {
   // inline callback function ...

   getSomeData(client, function (someData) {
      // another inline callback function ...

      getMoreData(client, function(moreData) {
         // one more inline callback function ...
      });
   });

   // etc ...
});

可以重写为如下所示:

var moreDataParser = function (moreData) {
   // date parsing logic
};

var someDataParser = function (someData) {
   // some data parsing logic

   getMoreData(client, moreDataParser);
};

var createServerCallback = function (req, res) {
   // create server logic

   getSomeData(client, someDataParser);

   // etc ...
};

http.createServer(createServerCallback);

但是,除非您计划在其他地方重用回调逻辑,否则阅读内联匿名函数通常要容易得多,如您的示例所示。它还将使您不必为所有回调查找名称。

另外请注意,正如@pst在下面的评论中指出的那样,如果您正在访问内部函数中的闭包变量,则上述内容将不是简单的翻译。在这种情况下,使用内联匿名函数更可取。


答案 2

Kay,只需使用这些模块之一即可。

它将变成这个:

dbGet('userIdOf:bobvance', function(userId) {
    dbSet('user:' + userId + ':email', 'bobvance@potato.egg', function() {
        dbSet('user:' + userId + ':firstName', 'Bob', function() {
            dbSet('user:' + userId + ':lastName', 'Vance', function() {
                okWeAreDone();
            });
        });
    });
});

进入这个:

flow.exec(
    function() {
        dbGet('userIdOf:bobvance', this);

    },function(userId) {
        dbSet('user:' + userId + ':email', 'bobvance@potato.egg', this.MULTI());
        dbSet('user:' + userId + ':firstName', 'Bob', this.MULTI());
        dbSet('user:' + userId + ':lastName', 'Vance', this.MULTI());

    },function() {
        okWeAreDone()
    }
);