Node.js:如何处理循环中的回调?

Node.js:如何处理循环中的回调?,node.js,for-loop,asynchronous,Node.js,For Loop,Asynchronous,我正在使用Node.js和Box SDK。我的(失败!)代码如下所示: var connection = box.getConnection(req.user.login); connection.ready(function () { connection.getFolderItems(0, null, function (err, result) { if (err) { opts.body = err; } else { opts.body =

我正在使用Node.js和Box SDK。我的(失败!)代码如下所示:

var connection = box.getConnection(req.user.login);
connection.ready(function () {
  connection.getFolderItems(0, null, function (err, result) {
    if (err) {
      opts.body = err;
    } else {
      opts.body = result;
      var a = [];
      for (var i=0; i < result.entries.length; i++) {
        connection.getFileInfo(result.entries[i].id, function (err, fileInfo) {
        if (err) {
          opts.body = err;
        } else {
          a.push(fileInfo);
        }
      });}
    }
var Promise = require('bluebird');
var connection = Promise.promisifyAll(box.getConnection(req.user.login));
connection.ready(function() {
    connection.getFolderItemsAsync(0, null).then(function(result) {
        return Promise.map(result.entries, function(item) {
            return connection.getFileInfoAsync(item.id).catch(function(err){
                // post the results as null and continue with the other results
                return null;
            });
        })
    }).then(function(results) {
        // array of results here (some might be null if they had an error)
    }, function(err) {
        // error here
    });
});
我的问题是
connection.getFolderItems()
connection.getFileInfo()
是异步的-在返回所有结果之前,“for”循环退出

问:在Node.js中,1)获取第一个异步调用的结果,2)遍历列表,进行更多异步调用,以及3)在“完成”所有操作后处理结果的最佳方法是什么

问:你在这里是个不错的选择吗

问:这是一种选择吗

问:Node.js中是否有针对此类场景的“标准习惯用法”

问:在Node.js中,获得第一个结果的最佳方法是什么 异步调用,2)遍历列表,进行更多异步调用,以及 3) 当一切都“完成”时处理结果

有多种方法。手工编码,承诺,异步库。“最好的”是在旁观者的眼里,所以我们在这里不是真的要说。我所有的异步编码都使用承诺。它们已经在ES6中正式标准化,并且有很好的、健壮的实现(我喜欢Bluebird,因为它在简化复杂异步任务的标准之外还有一些额外的特性,还有它的
promisifyAll()
功能,为使用异步回调调用约定的任何标准异步操作提供承诺接口)

我建议不要手工编写复杂的异步操作,因为健壮的错误处理非常困难,异常可以在异步回调中被默默地吃掉,从而导致错误处理丢失和调试困难。异步库可能是最好的非承诺方式,因为它围绕异步回调提供了一些基础结构和同步功能

我个人更喜欢承诺。我认为随着时间的推移,我们将看到更多的异步API在返回承诺方面实现标准化,因此我认为这是一种更好的前瞻性学习和编程方法

问:承诺在这里是一个好的选择吗

是的,Promission允许您运行一系列异步操作,然后使用类似于
Promise.all()
的方法来知道它们何时完成。它还将为您收集所有异步操作的所有结果

问:done()/next()是选项吗

我不太清楚您在这里问的是什么,但是您可以手动编写异步操作代码,使其并行运行并知道何时完成,或者按顺序运行并知道何时完成。承诺可以为您完成更多这方面的工作,但您可以在没有承诺的情况下手动完成

问:Node.js中是否有针对此类场景的“标准习惯用法”

如果使用承诺,将有一个共同的方式来做到这一点。如果不使用承诺,可能就没有“标准习惯用法”,因为有许多不同的方法可以自己编写

承诺实施

下面是一个使用node.js中的Bluebird Promise库的示例:

var Promise = require('bluebird');
var connection = Promise.promisifyAll(box.getConnection(req.user.login));
connection.ready(function() {
    connection.getFolderItemsAsync(0, null).then(function(result) {
        return Promise.map(result.entries, function(item) {
            return connection.getFileInfoAsync(item.id);
        })
    }).then(function(results) {
        // array of results here
    }, function(err) {
        // error here
    });
});
下面是它的工作原理:

  • Promisify连接对象,使其所有方法都有一个返回承诺的版本(只需在方法末尾添加“Async”即可调用此promisified版本)

  • 调用
    getFolderItemsAsync()
    ,它的承诺将通过
    结果来解决

  • 运行该数组的映射,并行运行所有操作,并在所有操作完成后返回一个承诺,该承诺将使用一个有序结果数组进行解析

  • 每个条目的实际结果是通过
    connection.getFileInfoAsync()
    实现的

  • 创建解析处理程序和拒绝处理程序。如果流程中的任何地方发生错误,它将传播到拒绝处理程序。如果所有操作都成功,将使用结果的有序数组调用最后一个解析处理程序

  • 如果出现错误,并且除错误代码外,没有其他结果,则上述版本将中止。如果您想在出现错误时继续使用
    null
    结果,则可以使用以下方法:

    var connection = box.getConnection(req.user.login);
    connection.ready(function () {
      connection.getFolderItems(0, null, function (err, result) {
        if (err) {
          opts.body = err;
        } else {
          opts.body = result;
          var a = [];
          for (var i=0; i < result.entries.length; i++) {
            connection.getFileInfo(result.entries[i].id, function (err, fileInfo) {
            if (err) {
              opts.body = err;
            } else {
              a.push(fileInfo);
            }
          });}
        }
    
    var Promise = require('bluebird');
    var connection = Promise.promisifyAll(box.getConnection(req.user.login));
    connection.ready(function() {
        connection.getFolderItemsAsync(0, null).then(function(result) {
            return Promise.map(result.entries, function(item) {
                return connection.getFileInfoAsync(item.id).catch(function(err){
                    // post the results as null and continue with the other results
                    return null;
                });
            })
        }).then(function(results) {
            // array of results here (some might be null if they had an error)
        }, function(err) {
            // error here
        });
    });
    

    手动编码版本

    这是一个手动编码的版本。这个问题的关键是通过比较
    if(results.length==result.entries.length)
    来检测异步循环何时完成。注意:这有不完整的错误处理,这是手工编码和不使用异步框架(如Promissions)的困难之一

    var connection = box.getConnection(req.user.login);
    connection.ready(function () {
        connection.getFolderItems(0, null, function (err, result) {
            if (err) {
                // do error handling here
                opts.body = err;
            } else {
                var results = [];
                for (var i = 0; i < result.entries.length; i++) {
                    connection.getFileInfo(result.entries[i].id, function (err, fileInfo) {
                        if (err) {
                            // do error handling here
                            opts.body = err;
                            results.push(null);
                        } else {
                            results.push(fileInfo);
                        }
                        // if done with all requests
                        if (results.length === result.entries.length) {
                            // done with everything, results are in results
                            // process final results here
                        }
                    });
                }
            }
        });
    });
    
    var connection=box.getConnection(请求用户登录);
    connection.ready(函数(){
    getFolderItems(0,null,函数(err,result){
    如果(错误){
    //请在此处执行错误处理
    opts.body=err;
    }否则{
    var结果=[];
    对于(var i=0;i
    问:在Node.js中,获得第一个结果的最佳方法是什么 异步调用,2)遍历列表,进行更多异步调用,以及 3) 当一切都“完成”时处理结果

    您可以使用库或promisify函数调用并使用Promise。两者都很容易使用

    问:承诺在这里是一个好的选择吗

    对。但它要求你在使用之前先提出你的方法

    Q:Is done()/next