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

Javascript 如何使用Promise.all获取URL数组?,javascript,promise,es6-promise,fetch-api,Javascript,Promise,Es6 Promise,Fetch Api,如果我有一个URL数组: var urls = ['1.txt', '2.txt', '3.txt']; // these text files contain "one", "two", "three", respectively. 我想构建一个如下所示的对象: var text = ['one', 'two', 'three']; 我一直在学习如何使用fetch,它当然会返回Promises 我尝试过一些不起作用的事情: 这看起来不对,而且在任何情况下都不起作用-我不会以数组['1'、'

如果我有一个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

我尝试过一些不起作用的事情:

这看起来不对,而且在任何情况下都不起作用-我不会以数组['1'、'2'、'3']结束


使用
Promise.all
是正确的方法吗

是的,
Promise.all
是正确的方法,但是如果您想首先
获取
所有URL,然后从URL获取所有
文本(这也是响应主体的承诺),那么实际上需要它两次。所以你需要这样做

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 => {
    …
})

出于某种原因,Bergi的两个例子都不适合我。它只会给我空洞的结果。在一些调试之后,它似乎会在获取完成之前返回承诺,因此结果是空的

然而,本杰明·格伦鲍姆(Benjamin Grunbaum)早些时候在这里有一个答案,但删除了它。他的方法确实对我有用,所以我将复制粘贴到这里,作为一种替代方法,以防其他人在第一个解决方案中遇到任何问题

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 => {
    // ...
});

建议的数组
URL=['1.txt',2.txt',3.txt']
没有多大用处 对我来说很有意义,因此我将使用:

url=[]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”,
“已完成”:false}
{“userId”:1,“id”:3,“title”:“fugiat veniam减”,“completed”:false}
目标是获得一个对象数组,其中每个对象都包含
标题
来自相应URL的值

为了让它更有趣一点,我假设已经有一个 我希望URL结果(标题)数组为的名称数组 合并为:

namesonly=['two','three']
所需的输出是一个对象数组:

[{“姓名”:“两个”,“知识点”:“我不知道该怎么办”},
{“姓名”:“三”,“loremipsum”:“福吉亚威尼斯减”}]
其中,我已将属性名称
title
更改为
loremipsum

constnamesonly=['two','three'];
常量URL=['https://jsonplaceholder.typicode.com/todos/2',
'https://jsonplaceholder.typicode.com/todos/3'];
Promise.all(url.map)(url=>fetch(url)
.then(response=>response.json())
.然后(responseBody=>responseBody.title)))
。然后(标题=>{
const names=namesonly.map(value=>({name:value}));
log('names:'+JSON.stringify(names));
const fakeLatins=titles.map(value=>({loremipsum:value}));
log('fakeLatins:\n'+JSON.stringify(fakeLatins));
常数结果=
names.map((item,i)=>Object.assign({},item,fakeLatins[i]);
log('result:\n'+JSON.stringify(result));
})
.catch(错误=>{
错误('无法获取一个或多个URL:');
日志(URL);
控制台错误(err);
});

。作为控制台包装{max height:100%!important;top:0;}
这看起来像是一个括号错误。你真的打算调用
。然后调用
。forEach(…)
的返回值,或者更确切地说调用
…text()
?你在哪里查看/log
文本
并观察到它仍然是空的?解决我在问题中感觉到的问题:你不能“提取”由于async在JavaScript中的工作方式,因此将结果转换为外部变量,但您可以使用Generator或async/await对其进行模拟。有关JS中异步性的完整指南,请参阅。这看起来很神奇!但我无法理解:(javascript是一种奇怪的语言language@sansSpoon你确定你在我的回答中使用了我的简明箭头体吗?它确实隐式地返回了承诺。当然,Doh,palm>face。我总是混合我的es5/6。谢谢。@1252748是的,
promise.all()
返回数组或响应对象的单个承诺。但是,
responses.map(res=>res.text())
生成另一个数组,该数组需要第二个
承诺。所有
。为什么使用map而不是forEach?只是问一下?@ChristianMatthew
map
返回
获取(url)的每个结果
forEach
不返回任何内容。请查看已接受的答案或。谢谢@HoldenLewis这是我一直在想的答案谢谢你,我已经查看了几个关于仅在承诺任务后才做某事的SO答案实际上已完成工作。此答案实际上是在触发回调之前等待所有文件完成获取。您的(/Benjamin Grunbaum)答案与Bergi的第二个代码片段之间实际上没有区别。-假设我将您的第二个
承诺
替换为
url.map(url=>fetch(url)。然后(y=>y.text())
然后用
resp
替换你的
y
,最后用
文本替换你的
结果
。与Bergi的第二个片段唯一的区别是注释
//对结果做点什么
,以及行中断的地方(以及最后的分号)。(这能解释为什么本杰明·格伦鲍姆删除了他的答案吗?)
Promise.all(urls.map(url => fetch(url)))
.then(resp => Promise.all( resp.map(r => r.text()) ))
.then(result => {
    // ...
});