在 JavaScript 中,在循环中使用 await 会阻塞循环吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/44410119/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In JavaScript, does using await inside a loop block the loop?
提问by smorgs
Take the following loop:
采取以下循环:
for(var i=0; i<100; ++i){
let result = await some_slow_async_function();
do_something_with_result();
}
Does
awaitblock the loop? Or does theicontinue to be incremented whileawaiting?Is the order of
do_something_with_result()guaranteed sequential with regard toi? Or does it depend on how fast theawaited function is for eachi?
是否
await阻塞循环?还是i在awaiting 时继续增加?do_something_with_result()关于 的顺序是否有保证i?还是取决于await每个 ed 函数的速度i?
回答by trincot
- Does
awaitblock the loop? Or does theicontinue to be incremented whileawaiting?
- 是否
await阻塞循环?还是i在awaiting 时继续增加?
"Block" is not the right word, but yes, idoes not continue to be incremented while awaiting. Instead the execution jumps back to where the asyncfunction was called, providing a promise as return value, continuing the rest of the code that follows after the function call, until the code stack has been emptied. Then when the awaiting is over, the state of the function is restored, and execution continues within that function. Whenever that function returns (completes), the corresponding promise -- that was returned earlier on -- is resolved.
“阻止”不是正确的词,但是是的,我在等待时不会继续递增。相反,执行会跳回到async函数被调用的地方,提供一个 promise 作为返回值,继续执行函数调用之后的其余代码,直到代码堆栈被清空。然后当等待结束时,恢复函数的状态,并在该函数内继续执行。每当该函数返回(完成)时,相应的承诺——之前返回的——就会被解析。
- Is the order of
do_something_with_result()guaranteed sequential with regard toi? Or does it depend on how fast theawaited function is for eachi?
do_something_with_result()关于 的顺序是否有保证i?还是取决于await每个 ed 函数的速度i?
The order is guaranteed. The code following the awaitis also guaranteed to execute only after the call stack has been emptied, i.e. at least on or after the next microtask can execute.
订单是有保证的。后面的代码await也保证只有在调用堆栈被清空后才执行,即至少在下一个微任务可以执行时或之后执行。
See how the output is in this snippet. Note especially where it says "after calling test":
查看此代码段中的输出如何。特别注意它说“在调用测试之后”:
async function test() {
for (let i = 0; i < 2; i++) {
console.log('Before await for ', i);
let result = await Promise.resolve(i);
console.log('After await. Value is ', result);
}
}
test().then(_ => console.log('After test() resolved'));
console.log('After calling test');
回答by Kris Selbekk
As @realbart says, it does block the loop, which then will make the calls sequential.
正如@realbart 所说,它确实阻塞了循环,然后使调用顺序进行。
If you want to trigger a ton of awaitable operations and then handle them all together, you could do something like this:
如果你想触发大量等待操作,然后一起处理它们,你可以这样做:
const promisesToAwait = [];
for (let i = 0; i < 100; i++) {
promisesToAwait.push(fetchDataForId(i));
}
const responses = await Promise.all(promisesToAwait);
回答by mzalazar
You can test async/await inside a "FOR LOOP" like this:
您可以像这样在“FOR LOOP”中测试异步/等待:
(async () => {
for (let i = 0; i < 100; i++) {
await delay();
console.log(i);
}
})();
function delay() {
return new Promise((resolve, reject) => {
setTimeout(resolve, 100);
});
}
回答by Kamil Kie?czewski
ad 1. Yes. No.
广告 1. 是的。不。
ad 2. Yes. No.
广告 2. 是的。不。
Proof:
证明:
async function start()
{
console.log('Start');
for (var i = 0; i < 10; ++i) {
let result = await some_slow_async_function(i);
do_something_with_result(i);
}
console.log('Finish');
}
function some_slow_async_function(n) {
return new Promise(res => setTimeout(()=>{
console.log(`Job done: ${(2000/(1+n))|0} ms`);
res(true);
},2000/(1+n)));
}
function do_something_with_result(n) {
console.log(`Something ${n}`);
}
start();
回答by Chris Bao
Here is my test solution about this interesting question:
这是我关于这个有趣问题的测试解决方案:
import crypto from "crypto";
function diyCrypto() {
return new Promise((resolve, reject) => {
crypto.pbkdf2('secret', 'salt', 2000000, 64, 'sha512', (err, res) => {
if (err) {
reject(err)
return
}
resolve(res.toString("base64"))
})
})
}
setTimeout(async () => {
console.log("before await...")
const a = await diyCrypto();
console.log("after await...", a)
}, 0);
setInterval(() => {
console.log("test....")
}, 200);
Inside the setTimeout's callback the awaitblocks the execution. But the setIntervalis keep runnning, so the Event Loop is running as usual.
在 setTimeout 的回调中,会await阻止执行。但是setInterval一直在运行,所以事件循环照常运行。
回答by KBH
No Event loop isn't blocked, see example below
没有事件循环未被阻止,请参见下面的示例
function sayHelloAfterSomeTime (ms) {
return new Promise((resolve, reject) => {
if (typeof ms !== 'number') return reject('ms must be a number')
setTimeout(() => {
console.log('Hello after '+ ms / 1000 + ' second(s)')
resolve()
}, ms)
})
}
async function awaitGo (ms) {
await sayHelloAfterSomeTime(ms).catch(e => console.log(e))
console.log('after awaiting for saying Hello, i can do another things ...')
}
function notAwaitGo (ms) {
sayHelloAfterSomeTime(ms).catch(e => console.log(e))
console.log('i dont wait for saying Hello ...')
}
awaitGo(1000)
notAwaitGo(1000)
console.log('coucou i am event loop and i am not blocked ...')
回答by Casey
asyncfunctions return a Promise, which is an object that will eventually "resolve" to a value, or "reject" with an error. The awaitkeyword means to wait until this value (or error) has been finalized.
async函数返回一个 Promise,它是一个最终将“解析”为一个值或“拒绝”并带有错误的对象。该await关键字表示要等到这个值(或错误)已经完成。
So from the perspective of the running function, it blocks waiting for the result of the slow async function. The javascript engine, on the other hand, sees that this function is blocked waiting for the result, so it will go check the event loop (ie. new mouse clicks, or connection requests, etc.) to see if there are any other things it can work on until the results are returned.
所以从运行函数的角度来看,它阻塞等待慢 async 函数的结果。另一方面,javascript引擎看到这个函数被阻塞等待结果,所以它会去检查事件循环(即新的鼠标点击,或连接请求等),看看是否还有其他事情它可以继续工作,直到返回结果。
Note however, that if the slow async function is slow because it is computing lots of stuff in your javascript code, the javascript engine won't have lots of resources to do other stuff (and by doing other stuff would likely make the slow async function even slower). Where the benefit of async functions really shine is for I/O intensive operations like querying a database or transmitting a large file where the javascript engine is well and truly waiting on something else (ie. database, filesystem, etc.).
但是请注意,如果慢速 async 函数很慢,因为它会在您的 javascript 代码中计算大量内容,则 javascript 引擎将没有大量资源来执行其他操作(并且通过执行其他操作可能会使慢速 async 函数甚至更慢)。异步函数的真正优势在于 I/O 密集型操作,例如查询数据库或传输大文件,其中 javascript 引擎真正在等待其他东西(即数据库、文件系统等)。
The following two bits of code are functionally equivalent:
以下两位代码在功能上是等效的:
let result = await some_slow_async_function();
and
和
let promise = some_slow_async_function(); // start the slow async function
// you could do other stuff here while the slow async function is running
let result = await promise; // wait for the final value from the slow async function
In the second example above the slow async function is called without the awaitkeyword, so it will start execution of the function and return a promise. Then you can do other things (if you have other things to do). Then the awaitkeyword is used to block until the promise actually "resolves". So from the perspective of the forloop it will run synchronous.
在上面的第二个示例中,在没有await关键字的情况下调用了慢速异步函数,因此它将开始执行该函数并返回一个承诺。然后你可以做其他事情(如果你有其他事情要做)。然后await关键字用于阻塞,直到承诺实际“解决”。所以从for循环的角度来看,它将同步运行。
So:
所以:
yes, the
awaitkeyword has the effect of blocking the running functionuntil the async function either "resolves" with a value or "rejects" with an error, but it does not block the javascript engine, which can still do other things if it has other things to do while awaitingyes, the execution of the loop will be sequential
是的,该
await关键字具有阻塞正在运行的函数的作用,直到异步函数用值“解决”或“拒绝”出现错误,但它不会阻塞 javascript 引擎,如果它有其他事情,它仍然可以做其他事情等待时要做的事情是的,循环的执行将是顺序的
There is an awesome tutorial about all this at http://javascript.info/async.
在http://javascript.info/async 上有一个关于所有这些的很棒的教程。
回答by DeeKay
Does await block the loop? Or does the
icontinue to be incremented while awaiting?
await 会阻塞循环吗?还是
i在等待时继续增加?
No, await won't block the looping. Yes, icontinues to be incremented while looping.
不, await 不会阻止循环。是的,i循环时继续递增。
Is the order of do_something_with_result() guaranteed sequential with regard to
i? Or does it depend on how fast the awaited function is for eachi?
do_something_with_result() 的顺序是否保证顺序
i?还是取决于等待的函数对每个函数的速度有多快i?
Order of do_something_with_result()is guaranteed sequentially but not with regards to i. It depends on how fast the awaited function runs.
的顺序do_something_with_result()是按顺序保证的,但不是关于i。这取决于等待的函数运行的速度。
All calls to some_slow_async_function()are batched, i.e., if do_something_with_result()was a consolethen we will see it printed the number of times the loop runs. And then sequentially, after this, all the await calls will be executed.
所有对的调用some_slow_async_function()都是批处理的,即,如果do_something_with_result()是 aconsole那么我们将看到它打印循环运行的次数。然后依次执行所有 await 调用。
To better understandyou can run below code snippet:
为了更好地理解,您可以运行以下代码片段:
async function someFunction(){
for (let i=0;i<5;i++){
await callAPI();
console.log('After', i, 'th API call');
}
console.log("All API got executed");
}
function callAPI(){
setTimeout(()=>{
console.log("I was called at: "+new Date().getTime())}, 1000);
}
someFunction();
One can clearly see how line console.log('After', i, 'th API call');gets printed first for entire stretch of the for loop and then at the end when all code is executed we get results from callAPI().
可以清楚地看到如何console.log('After', i, 'th API call');在整个 for 循环段中首先打印行,然后在执行所有代码时最后我们从callAPI().
So if lines after await were dependent on result obtained from await calls then they will not work as expected.
因此,如果 await 之后的行依赖于从 await 调用中获得的结果,那么它们将无法按预期工作。
To conclude, awaitin for-loopdoes not ensure successful operation on result obtained from await callswhich might take some time to finish.
总而言之,awaitinfor-loop并不能确保成功操作从await 调用获得的结果,这可能需要一些时间才能完成。
In node, if one uses neo-asynclibrary with waterfall, one can achieve this.
在节点中,如果使用neo-async带有 的库waterfall,则可以实现这一点。

