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

时间:2015-07-29 20:46:21

标签: javascript promise es6-promise fetch-api

如果我有一系列网址:

var urls = ['1.txt', '2.txt', '3.txt']; // these text files contain "one", "two", "three", respectively.

我想建立一个看起来像这样的对象:

var text = ['one', 'two', 'three'];

我一直在努力学习fetch,这当然会返回Promise

我尝试了工作的一些事情:

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

这看起来不对,无论如何它都不起作用 - 我最终没有数组['一个','两个',&# 39;三'。]

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

4 个答案:

答案 0 :(得分:73)

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

Promise.all(urls.map(u=>fetch(u))).then(responses =>
    Promise.all(responses.map(res => res.text()))
).then(texts => {
    …
})

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

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

Promise.all(urls.map(url =>
    fetch(url).then(resp => resp.text())
)).then(texts => {
    …
})

答案 1 :(得分:17)

由于某些原因,Bergi的例子都没有为我工作。它只会给我空洞的结果。经过一些调试之后,它会像在fetch完成之前返回一样,因此结果为空。

然而,Benjamin Gruenbaum早些时候在这里得到了答案,但删除了它。他的方法确实为我工作,所以我只是将其复制粘贴到此处,以防其他人遇到第一个解决方案的任何问题。

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

答案 2 :(得分:9)

您应该使用map代替forEach

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

答案 3 :(得分:2)

建议的数组 urls = ['1.txt', '2.txt', '3.txt'] 并不多 对我来说很有意义,所以我会改用:

urls = ['https://jsonplaceholder.typicode.com/todos/2',
        'https://jsonplaceholder.typicode.com/todos/3']

两个 URL 的 JSON:

{"userId":1,"id":2,"title":"quis ut nam facilis et officia qui",
 "completed":false}
{"userId":1,"id":3,"title":"fugiat veniam minus","completed":false}

目标是获取一个对象数组,其中每个对象包含title 来自相应 URL 的值。

为了让它更有趣,我假设已经有一个 我希望 URL 结果数组(titles)成为的 names 数组 合并:

namesonly = ['two', 'three']

所需的输出是一个对象数组:

[{"name":"two","loremipsum":"quis ut nam facilis et officia qui"},
{"name":"three","loremipsum":"fugiat veniam minus"}]

我已将属性名称 title 更改为 loremipsum

const namesonly = ['two', 'three'];
const urls = ['https://jsonplaceholder.typicode.com/todos/2',
  'https://jsonplaceholder.typicode.com/todos/3'];

Promise.all(urls.map(url => fetch(url)
  .then(response => response.json())
  .then(responseBody => responseBody.title)))
  .then(titles => {
    const names = namesonly.map(value => ({ name: value }));
    console.log('names: ' + JSON.stringify(names));
    const fakeLatins = titles.map(value => ({ loremipsum: value }));
    console.log('fakeLatins:\n' + JSON.stringify(fakeLatins));
    const result =
      names.map((item, i) => Object.assign({}, item, fakeLatins[i]));
    console.log('result:\n' + JSON.stringify(result));
  })
  .catch(err => {
    console.error('Failed to fetch one or more of these URLs:');
    console.log(urls);
    console.error(err);
  });
.as-console-wrapper { max-height: 100% !important; top: 0; }

参考