Nic*_*ian 24 javascript node.js promise async-await for-await
这有什么区别吗:
const promises = await Promise.all(items.map(e => somethingAsync(e)));
for (const res of promises) {
// do some calculations
}
Run Code Online (Sandbox Code Playgroud)
和这个 ?
for await (const res of items.map(e => somethingAsync(e))) {
// do some calculations
}
Run Code Online (Sandbox Code Playgroud)
我知道在第一个片段中,所有的承诺都被同时触发,但我不确定第二个。for 循环是否等待第一次迭代完成以调用下一个 promise ?还是所有的 Promise 都是同时触发的,循环内部就像是它们的回调?
Ber*_*rgi 19
是的,它们完全不同。for await应该与异步迭代器一起使用,而不是与预先存在的承诺数组一起使用。
只是为了说明,
for await (const res of items.map(e => somethingAsync(e))) …
Run Code Online (Sandbox Code Playgroud)
工作原理相同
const promises = items.map(e => somethingAsync(e));
for await (const res of promises) …
Run Code Online (Sandbox Code Playgroud)
或者
const promises = [somethingAsync(items[0]), somethingAsync(items[1]), …];
for await (const res of promises) …
Run Code Online (Sandbox Code Playgroud)
该somethingAsync呼叫将立即发生,一次全部,任何等待之前。然后,它们await一个接一个地被编辑,如果其中任何一个被拒绝,这绝对是一个问题:这将导致未处理的承诺拒绝错误。使用Promise.all是处理 promise 数组的唯一可行选择:
for (const res of await Promise.all(promises)) …
Run Code Online (Sandbox Code Playgroud)
请参阅等待多个并发等待操作和等待 Promise.all() 和多个等待之间有什么区别?详情。
Cas*_*ano 10
for await ...当在异步迭代器上当前迭代的计算依赖于一些先前的迭代时,需要出现。如果没有依赖,Promise.all就是你的选择。该for await构造旨在与异步迭代器一起使用,尽管 - 在您的示例中,您可以将它与一系列承诺一起使用。
有关使用无法使用以下方法重写的异步迭代器的示例,请参阅javascript.info一书中的示例分页数据:Promise.all
(async () => {
for await (const commit of fetchCommits('javascript-tutorial/en.javascript.info')) {
console.log(commit.author.login);
}
})();
Run Code Online (Sandbox Code Playgroud)
这里fetchCommits异步迭代器向fetchGitHub 存储库的提交发出请求。在fetch与30个提交一个JSON响应,并且还提供了一个链接到下一个页面Link标题。因此下一次迭代只能在上一次迭代有下一个请求的链接后开始
async function* fetchCommits(repo) {
let url = `https://api.github.com/repos/${repo}/commits`;
while (url) {
const response = await fetch(url, {
headers: {'User-Agent': 'Our script'},
});
const body = await response.json(); // (array of commits
// The URL of the next page is in the headers, extract it using a regexp
let nextPage = response.headers.get('Link').match(/<(.*?)>; rel="next"/);
nextPage = nextPage?.[1];
url = nextPage;
for(let commit of body) { // yield commits one by one, until the page ends
yield commit;
}
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所说,Promise.all将一次性发送所有请求,然后在所有请求完成后您将收到响应。
在第二种情况下,您将一次性发送请求,但会一一收到响应。
请参阅此小示例以供参考。
let i = 1;
function somethingAsync(time) {
console.log("fired");
return delay(time).then(() => Promise.resolve(i++));
}
const items = [1000, 2000, 3000, 4000];
function delay(time) {
return new Promise((resolve) => {
setTimeout(resolve, time)
});
}
(async() => {
console.time("first way");
const promises = await Promise.all(items.map(e => somethingAsync(e)));
for (const res of promises) {
console.log(res);
}
console.timeEnd("first way");
i=1; //reset counter
console.time("second way");
for await (const res of items.map(e => somethingAsync(e))) {
// do some calculations
console.log(res);
}
console.timeEnd("second way");
})();
Run Code Online (Sandbox Code Playgroud)
您也可以在这里尝试 - https://repl.it/repls/SuddenUselessAnalyst
希望这可以帮助。