【问题标题】:Array of promise with results separately分别带有结果的承诺数组
【发布时间】:2016-11-12 12:16:00
【问题描述】:

基本上,我正在寻找类似Promise.all() 的东西,但只要结果准备好,它就会为每个结果调用then() 中的函数。使用像这样的标准回调编写是微不足道的(文件读取示例):

function foo(files, bar) {
  for (let file of files) {
    const fr = new FileReader();
    fr.onload = e => bar(e.target.result);
    fr.readAsDataURL(file);
  }
}

我确定那里有一个库可以满足我的需求,但我想用纯 JS 来实现。

为了澄清,我想要这样的东西:

function foo(files) {
  // do something here;
}

foo(['1','2','3']).then(/* do something here with separate results */);`

【问题讨论】:

  • forEach 数组方法是否满足您的要求? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • 这意味着我在调用 Promise 函数后无法编写简单的 .then()。
  • 您介意添加一个示例来演示它是如何不起作用的吗? jib 下面的回答似乎适合我的 POV
  • 你为什么不做 promise.race 来获得第一个结果,然后用 promise.all 来做剩下的。

标签: javascript arrays callback promise ecmascript-6


【解决方案1】:

只需使用map:

let read = file => return new Promise(resolve => {
  const fr = new FileReader();
  fr.onload = e => resolve(e.target.result);
  fr.readAsDataURL(file);
});

Promise.all(files.map(file => read(file).then(bar)))
  .then(allResultsFromBar => { /* use results array */ });

请注意,.then 将从它执行的函数返回的任何内容提升为一个承诺(即它隐式调用Promise.resolve),因此无论bar 返回什么,Promise.all 都保证接收到一组承诺.

【讨论】:

  • 但是map需要返回promise。缺少对此的解释
  • 确实如此,因为.then 将其执行的函数返回的任何内容提升为承诺(即它隐式调用Promise.resolve。)
  • 那是bar,每次准备好结果时都会调用它。
  • 很好的答案 - 一点。你想让read 中的new Promise 包装整个函数,而不仅仅是最后一行,如果readAsDataUrl 同步抛出,你必须同时处理同步和异步拒绝。
  • @Krzaku 最好坚持通用/标准编程模式:)
【解决方案2】:

根据@jib 的回答和评论工作:

我想要一个函数 readFiles,它接受一个文件列表作为它的唯一参数,我希望它返回某种我可以调用 then() 的承诺,以及我将放入 then( ) 将为每个文件单独调用。

这不太可能,因为.then() 回调只被调用一次,而不是Promise.all() 传递的每个结果一次。

这很接近:

let read = file => return new Promise((resolve, reject) => {
    const fr = new FileReader();
    fr.onload = e => resolve(e.target.result);
    fr.onerror = reject; // don't forget to reject on error
    fr.readAsDataURL(file);
});

let readFiles = files => return Promise.all(files.map(read)); // <<<<< this is the line you seek

允许你写:

const files = ["...", "...", "..."];
readFiles(files)
.then(allFileResults => allFileResults.map(bar)); // bar is your function for processing file results
// possibly chain another .then() if required to observe/process bar()'s results

因此bar()将依次对每个文件内容进行操作。

但是,为了让代码尽可能接近您的要求:

  • 您的“尽快”要求并未真正满足; allFileContents.map(bar) 进程在 Promise.all() 的下游,因此在开始 bar() 调用之前等待所有文件被读取。
  • readFiles(...) 中的任何单个错误都会(没有某种错误恢复)破坏整个企业; allFileContents.map(bar) 永远不会在任何文件上被调用;根据您的应用程序,这可能是好是坏;不过好消息是,错误恢复很容易插入。
  • 如所写,bar() 必须是同步的;如果没有,您可以简单地插入另一个Promise.all(),即allFileResults =&gt; Promise.all(allFileResults.map(bar))

出于这些原因,@jib 的解决方案很可能是一种解决方案,但这取决于应用程序的需求。

【讨论】:

    猜你喜欢
    • 2017-06-25
    • 1970-01-01
    • 2016-07-30
    • 1970-01-01
    • 1970-01-01
    • 2018-08-30
    • 2017-12-14
    • 1970-01-01
    相关资源
    最近更新 更多