采取以下循环:
for(var i=0; i<100; ++i){
let result = await some_slow_async_function();
do_something_with_result();
}
是否
await
阻塞循环?还是i
在await
ing 时继续增加?do_something_with_result()
关于 的顺序是否有保证i
?还是取决于await
每个 ed 函数的速度i
?
采取以下循环:
for(var i=0; i<100; ++i){
let result = await some_slow_async_function();
do_something_with_result();
}
是否await
阻塞循环?还是i
在await
ing 时继续增加?
do_something_with_result()
关于 的顺序是否有保证i
?还是取决于await
每个 ed 函数的速度i
?
- 是否
await
阻塞循环?还是i
在await
ing 时继续增加?
“阻止”不是正确的词,但是是的,在等待时i不会继续递增。相反,执行会跳回到async
函数被调用的地方,提供一个 promise 作为返回值,继续执行函数调用之后的其余代码,直到代码堆栈被清空。然后当等待结束时,恢复函数的状态,并在该函数内继续执行。每当该函数返回(完成)时,相应的Promise——之前返回的——就会被解析。
do_something_with_result()
关于 的顺序是否有保证i
?还是取决于await
每个 ed 函数的速度i
?
订单是有保证的。后面的代码await
也保证只有在调用堆栈被清空后才执行,即至少在下一个微任务可以执行时或之后执行。
查看此代码段中的输出如何。特别注意它说“在调用测试之后”:
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');
正如@realbart 所说,它确实阻塞了循环,然后使调用顺序进行。
如果你想触发大量等待操作,然后一起处理它们,你可以这样做:
const promisesToAwait = [];
for (let i = 0; i < 100; i++) {
promisesToAwait.push(fetchDataForId(i));
}
const responses = await Promise.all(promisesToAwait);
您可以像这样在“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);
});
}
async
函数返回一个 Promise,它是一个最终将“解析”为一个值或“拒绝”并带有错误的对象。该await
关键字表示要等到这个值(或错误)已经完成。
所以从运行函数的角度来看,它阻塞等待慢 async 函数的结果。另一方面,javascript引擎看到这个函数被阻塞等待结果,所以它会去检查事件循环(即新的鼠标点击,或连接请求等),看看是否还有其他事情它可以继续工作,直到返回结果。
但是请注意,如果慢速异步函数很慢,因为它正在计算您的 javascript 代码中的大量内容,则 javascript 引擎将没有大量资源来执行其他操作(并且通过执行其他操作可能会使慢速异步函数甚至更慢)。异步函数的真正优势在于 I/O 密集型操作,例如查询数据库或传输大文件,其中 javascript 引擎真正地等待其他东西(即数据库、文件系统等)。
以下两位代码在功能上是等效的:
let result = await some_slow_async_function();
和
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
在上面的第二个示例中,在没有await
关键字的情况下调用了慢速异步函数,因此它将开始执行该函数并返回一个Promise。然后你可以做其他事情(如果你有其他事情要做)。然后await
关键字用于阻塞,直到Promise实际“解决”。所以从for
循环的角度来看,它将同步运行。
所以:
是的,该await
关键字具有阻塞正在运行的函数的作用,直到异步函数用值“解析”或“拒绝”出现错误为止,但它不会阻塞 javascript 引擎,如果它有其他事情,它仍然可以做其他事情等待时要做的事情
是的,循环的执行将是顺序的
http://javascript.info/async 上有一个关于所有这些的很棒的教程。
这是我关于这个有趣问题的测试解决方案:
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);
在 setTimeout 的回调中,会await
阻止执行。但是setInterval
一直在运行,所以事件循环照常运行。