如何使用Promise.all获取URL数组?

46 javascript promise es6-promise fetch-api

如果我有一个网址数组:

var urls = ['1.txt', '2.txt', '3.txt']; // these text files contain "one", "two", "three", respectively.
Run Code Online (Sandbox Code Playgroud)

我想构建一个如下所示的对象:

var text = ['one', 'two', 'three'];
Run Code Online (Sandbox Code Playgroud)

我一直在努力学习如何做到这一点fetch,这当然会回归Promises.

有些事情我已经试过了工作:

var promises = urls.map(url => fetch(url));
var texts = [];
Promise.all(promises)
  .then(results => {
     results.forEach(result => result.text()).then(t => texts.push(t))
  })
Run Code Online (Sandbox Code Playgroud)

这看起来不对,无论如何它都不起作用 - 我最终没有数组['one','two','three'].

Promise.all在这里使用正确的方法?

Ber*_*rgi 87

是的,这Promise.all是正确的方法,但如果您想要首先fetch获取所有网址然后从中获取所有网址text(这也是响应正文的承诺),您实际上需要它两次.所以你需要这样做

Promise.all(urls.map(u=>fetch(u))).then(responses =>
    Promise.all(responses.map(res => res.text()))
).then(texts => {
    …
})
Run Code Online (Sandbox Code Playgroud)

您当前的代码无效,因为forEach什么都不返回(既不是数组也不是promise).

当然,您可以简化这一过程,然后在相应的获取承诺完成后立即从每个响应中获取正文:

Promise.all(urls.map(url =>
    fetch(url).then(resp => resp.text())
)).then(texts => {
    …
})
Run Code Online (Sandbox Code Playgroud)

  • 解决我在问题中感觉到的问题:由于JavaScript中的异步如何工作,您无法将结果"提取"到外部变量,但您可以使用生成器或async/await来模拟它.有关JS中异步性的完整指南,请参阅[此答案](http://stackoverflow.com/a/30180679/1348195). (3认同)

pei*_*rix 19

由于某些原因,Bergi的例子都不适合我.它只会给我空洞的结果.经过一些调试之后,它会像在fetch完成之前返回一样,因此空结果.

然而,Benjamin Gruenbaum早些时候在这里得到了答案,但删除了它.他的方法确实为我工作,所以我就在这里复制粘贴,因为万一别人替代运行到这里的第一个解决方案的任何问题.

var promises = urls.map(url => fetch(url).then(y => y.text()));
Promise.all(promises).then(results => {
    // do something with results.
});
Run Code Online (Sandbox Code Playgroud)


evg*_*gen 10

您应该使用map而不是forEach:

Promise.all(urls.map(url => fetch(url)))
.then(resp => Promise.all( resp.map(r => r.text()) ))
.then(result => {
    // ...
});
Run Code Online (Sandbox Code Playgroud)

  • 为什么使用 map 而不是 forEach?只是想问? (2认同)

Der*_*rek 7

这是一种干净的方法。

const requests = urls.map((url) => fetch(url)); 
const responses = await Promise.all(requests); 
const promises = responses.map((response) => response.text());
return await Promise.all(promises);
Run Code Online (Sandbox Code Playgroud)