如何使用 Promise.all 获取一组 URL?
How can I fetch an array of URLs with 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
,当然 returns 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
是正确的方法吗?
是的,Promise.all
是正确的方法,但如果您想首先 fetch
所有 url,然后从中获取所有 text
,实际上您需要它两次(这又是是响应主体的承诺)。所以你需要做
Promise.all(urls.map(u=>fetch(u))).then(responses =>
Promise.all(responses.map(res => res.text()))
).then(texts => {
…
})
您当前的代码无法正常工作,因为 forEach
returns 什么都没有(既不是数组也不是 promise)。
当然你可以简化它,并在各自的获取承诺完成后立即从每个响应中获取正文:
Promise.all(urls.map(url =>
fetch(url).then(resp => resp.text())
)).then(texts => {
…
})
或与 await
相同:
const texts = await Promise.all(urls.map(async url => {
const resp = await fetch(url);
return resp.text();
}));
出于某种原因,Bergi 的两个示例都不适合我。它只会给我空洞的结果。经过一些调试后,似乎承诺会在获取完成之前 return,因此结果为空。
然而,Benjamin Gruenbaum 早些时候在这里有一个答案,但将其删除。他的方法 did 对我有用,所以我只是将其复制粘贴到这里,以防万一其他人在使用第一个解决方案时遇到任何问题。
var promises = urls.map(url => fetch(url).then(y => y.text()));
Promise.all(promises).then(results => {
// do something with results.
});
你应该使用 map
而不是 forEach
:
Promise.all(urls.map(url => fetch(url)))
.then(resp => Promise.all( resp.map(r => r.text()) ))
.then(result => {
// ...
});
建议的数组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.
的值
为了让它更有趣一点,我假设已经有一个
names 数组,我希望 URL 结果数组(titles)是
合并于:
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; }
参考
以防万一,如果你使用的是 axios。我们可以这样实现:
const apiCall = (endpoint:string)=> axios.get(${baseUrl}/${endpoint}
)
axios.all([apiCall('https://first-endpoint'),apiCall('https://second-endpoint')]).then(response => {
response.forEach(values => values)
}).catch(error => {})
这是一个干净的方法。
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);
如果我有一个 url 数组:
var urls = ['1.txt', '2.txt', '3.txt']; // these text files contain "one", "two", "three", respectively.
我想构建一个如下所示的对象:
var text = ['one', 'two', 'three'];
我一直在努力学习如何使用 fetch
,当然 returns 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
是正确的方法吗?
是的,Promise.all
是正确的方法,但如果您想首先 fetch
所有 url,然后从中获取所有 text
,实际上您需要它两次(这又是是响应主体的承诺)。所以你需要做
Promise.all(urls.map(u=>fetch(u))).then(responses =>
Promise.all(responses.map(res => res.text()))
).then(texts => {
…
})
您当前的代码无法正常工作,因为 forEach
returns 什么都没有(既不是数组也不是 promise)。
当然你可以简化它,并在各自的获取承诺完成后立即从每个响应中获取正文:
Promise.all(urls.map(url =>
fetch(url).then(resp => resp.text())
)).then(texts => {
…
})
或与 await
相同:
const texts = await Promise.all(urls.map(async url => {
const resp = await fetch(url);
return resp.text();
}));
出于某种原因,Bergi 的两个示例都不适合我。它只会给我空洞的结果。经过一些调试后,似乎承诺会在获取完成之前 return,因此结果为空。
然而,Benjamin Gruenbaum 早些时候在这里有一个答案,但将其删除。他的方法 did 对我有用,所以我只是将其复制粘贴到这里,以防万一其他人在使用第一个解决方案时遇到任何问题。
var promises = urls.map(url => fetch(url).then(y => y.text()));
Promise.all(promises).then(results => {
// do something with results.
});
你应该使用 map
而不是 forEach
:
Promise.all(urls.map(url => fetch(url)))
.then(resp => Promise.all( resp.map(r => r.text()) ))
.then(result => {
// ...
});
建议的数组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.
为了让它更有趣一点,我假设已经有一个 names 数组,我希望 URL 结果数组(titles)是 合并于:
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; }
参考
以防万一,如果你使用的是 axios。我们可以这样实现:
const apiCall = (endpoint:string)=> axios.get(${baseUrl}/${endpoint}
)
axios.all([apiCall('https://first-endpoint'),apiCall('https://second-endpoint')]).then(response => {
response.forEach(values => values)
}).catch(error => {})
这是一个干净的方法。
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);