If I have an array of urls:
var urls = ['1.txt', '2.txt', '3.txt']; // these text files contain "one", "two", "three", respectively.
And I want to build an object that looks like this:
var text = ['one', 'two', 'three'];
I’ve been trying to learn to do this with fetch
, which of course returns Promise
s.
Some things I’ve tried that don’t work:
var promises = urls.map(url => fetch(url)); var texts = []; Promise.all(promises) .then(results => { results.forEach(result => result.text()).then(t => texts.push(t)) })
This doesn’t look right, and in any case it doesn’t work — I don’t end up with an array [‘one’, ‘two’, ‘three’].
Is using Promise.all
the right approach here?
Advertisement
Answer
Yes, Promise.all
is the right approach, but you actually need it twice if you want to first fetch
all urls and then get all text
s from them (which again are promises for the body of the response). So you’d need to do
Promise.all(urls.map(u=>fetch(u))).then(responses => Promise.all(responses.map(res => res.text())) ).then(texts => { … })
Your current code is not working because forEach
returns nothing (neither an array nor a promise).
Of course you can simplify that and start with getting the body from each response right after the respective fetch promise fulfilled:
Promise.all(urls.map(url => fetch(url).then(resp => resp.text()) )).then(texts => { … })
or the same thing with await
:
const texts = await Promise.all(urls.map(async url => { const resp = await fetch(url); return resp.text(); }));