【问题标题】:node.js async parallel function returns a single result several timesnode.js 异步并行函数多次返回单个结果
【发布时间】:2026-02-17 23:05:01
【问题描述】:

我正在尝试使用 node.js 的异步模块并行上传多个文件。我的代码如下所示:

// fileArr is an array of objects. each object contains the attributes of the file to be uploaded - filename, path, destination path, etc.

// toUpload is an array to which i push all the functions i want to execute with async.parallel

  for (i=0; i<fileArr.length; i++) {
    var src = fileArr[i]['path']
    var dest = fileArr[i]['dest']
    var fn = function(cb) { self.upload(src, dest, headers, function(err, url) { 
      cb(null, url)   
    })  
  }
  toUpload.push(fn) 
  } // for loop ends here

async.parallel(toUpload, function(err, results) {
  console.log('results: ' + results)
}) 

我的问题:对于 n = toUpload 中的函数数,结果数组回调包含数组中最后一个并行任务的结果,n 次。我想不通。似乎每个函数都应该使用 (null, url) 将自己的回调返回给并行函数。

还有 - 当我尝试使用 src 和 dest 的定义直接调用 self.upload 函数时:

self.upload(fileArr[i]['path'], fileArr[i]['dest'], headers, function(err, url) {
  cb(null, url)
})

我收到一条错误消息,提示“无法读取未定义的属性‘路径’”。所以,fileArr[i] 是未定义的。为什么会这样?我觉得任务和范围的进行有些奇怪......

如果问题(和代码)不是很明显,我对编程还是很陌生..

【问题讨论】:

    标签: node.js asynchronous


    【解决方案1】:

    请记住,这本质上是:

    var src, dest
    for (i=0; i<fileArr.length; i++) {
      src = fileArr[i]['path']
      dest = fileArr[i]['dest']
      var fn = function(cb) {
        self.upload(src, dest, headers, function(err, url) { 
          cb(null, url)   
      })  
    }
    

    这可能更清楚地表明,当您的 fn 函数被调用时,for 循环已经完成,因此 srcdest 将在每次调用 fn 时获得它们的最终循环值。

    同样,对于self.upload(fileArr[i]['path'], fileArr[i]['dest'], ...,当你的函数运行时,i === fileArr.length 的值因为 for 循环已经完成。

    最简单的解决方案是改用async.map

    async.map(
      fileArr,
      function(file, callback){
        self.upload(file['src'], file['dest'], headers, function(err, url){
          callback(null, url);
        });
      },
      function(err, results) {
        console.log('results: ' + results)
      }
    )
    

    我将 null 作为错误传递,因为这是您在示例中所做的,但您可能不应该丢弃错误,因为它们可能很重要。

    【讨论】:

    • 好的,这有帮助,但请稍等。我将 fn 推入我的并行数组中,以进行 for 循环的每次迭代。所以并行数组中的每个函数都应该有不同的参数,对吧?因为每次我将函数推送到数组时 src 和 dest 的值都不同?
    • fn 的每个实例都是一个新函数,但它引用了外部函数范围内的值。在函数实际执行之前,它不会使用这些值,在这种情况下,当它运行时,这些值已被循环的下一次迭代更改。
    • 是的!我更新了示例,这只是一个复制/粘贴错误。
    • 非常感谢。很好的解释 - 刚刚使用 .map 重新实现,效果很好。