一系列承诺与结果分开

时间:2016-07-10 12:30:00

标签: javascript arrays callback promise ecmascript-6

基本上,我正在寻找像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 */);`

2 个答案:

答案 0 :(得分:4)

只需使用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(即它隐式调用Promise.resolve),因此Promise.all保证接收一个promise数组no无论bar返回什么。

答案 1 :(得分:0)

使用@ jib的回答和评论:

  

我想要一个函数readFiles,它将文件列表作为唯一的参数,我希望它返回一些我可以调用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()将依次对每个文件内容进行操作。

然而,在使代码尽可能接近您的要求时:

  • 你的&#34;一旦&#34;要求并非真正满足; allFileContents.map(bar)进程位于Promise.all()的下游,因此在开始bar()调用之前,等待所有文件被读取。
  • readFiles(...)中的任何一个错误(没有某种错误恢复)会破坏整个企业;永远不会在任何文件上调用allFileContents.map(bar);根据您的申请,这可能是好的或坏的;但好消息是,很容易插入错误恢复。
  • 如上所述,bar()必须是同步的;如果没有,您只需插入另一个Promise.all(),即allFileResults => Promise.all(allFileResults.map(bar))

由于这些原因,@ jib的解决方案可能是最适合的解决方案,但这取决于应用程序的要求。