Как я могу получить массив URL-адресов с помощью Promise.all?

Если у меня есть массив URL-адресов:

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

И я хочу построить объект, который выглядит так:

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

Я пытался научиться делать это с помощью fetch, что, конечно же, возвращает Promise s.

Некоторые вещи, которые я пытался, не работают:

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

Это не выглядит правильным, и в любом случае он не работает - я не получаю массив ['one', 'two', 'three'].

Использует Promise.all правильный подход здесь?

Ответы

Ответ 1

Да, Promise.all - правильный подход, но он вам действительно нужен дважды, если вы хотите сначала fetch все URL-адреса, а затем получить от них весь 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 => {
    …
})

Ответ 2

По какой-то причине ни один из примеров Берги не работал для меня. Это просто даст мне пустые результаты. После некоторой отладки кажется, что обещание вернется до того, как выборка закончится, а значит, и пустые результаты.

Однако Бенджамин Груэнбаум ответил здесь ранее, но удалил его. Его метод действительно работал для меня, поэтому я просто скопирую его здесь, в качестве альтернативы, если кто-то еще столкнется с какими-либо проблемами с первым решением здесь.

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

Ответ 3

Вы должны использовать map вместо forEach:

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