javascript - 使用 async/await 时调用堆栈的工作
问题描述
使用 async/await 函数时调用堆栈的行为如何?
function resolveAfter2Seconds() { // taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
const asyncFuntion=async()=>{
const result = await resolveAfter2Seconds();
console.info("asyncFuntion finish, result is: ", result);
}
const first = async()=>{
await asyncFuntion();
console.log('first completed');
debugger;
}
const second = ()=>{
console.log('second completed');
debugger;
}
function main(){
first();
second();
}
main();
在上面的代码中,当在 second() 中遇到第一个断点时,我可以看到调用堆栈包含 main() 和 second()。在 first() 中的第二个断点期间,调用堆栈包含 main() 和 first()。
在第一个断点期间 first() 发生了什么。推到哪里去了?假设 asyncFunction() 需要一些时间才能完成。
有人请帮忙。
解决方案
首先,当你到达你点击的断点时second
,first
已经执行并且不再在堆栈上。
当我们进入时first
,我们立即击中了一个await asyncFunction()
。这告诉 JavaScript 不要阻塞调用的结果,但在我们等待的时候可以随意寻找其他事情要做。Javascript 是做什么的?
嗯,首先,它确实调用了asyncFunction()
. 这将返回一个承诺,并将启动一些稍后将解决它的异步过程。现在我们不能继续下一行first
(即 the console.log('first completed')
),因为我们的await
意思是在承诺完成之前我们不能继续,所以我们需要在这里暂停执行,然后找点空闲时间做点别的事情。
所以,我们查找堆栈。我们仍然在first()
来自 main 的调用中,现在我们可以从该调用中返回一个 Promise,我们将在异步执行完成时解决它。main
忽略该承诺返回值,因此我们继续使用second()
. 一旦我们执行完毕second
,我们就回顾一下所谓的那个,并以每个人都期望的方式继续同步执行。
然后,在未来的某个时刻,我们的承诺实现了。也许它正在等待 API 调用返回。也许它正在等待数据库回复它。在我们的示例中,它正在等待 2 秒超时。无论它在等待什么,现在都可以处理了,我们可以取消暂停first
调用并继续在那里执行。它不是从内部“调用”的main
——函数在内部被拾取,就像回调一样,但关键是用一个全新的堆栈调用,一旦我们完成调用函数的其余部分,它将被销毁。
鉴于我们在一个新堆栈中,并且早已离开“主”堆栈框架,当我们在其中遇到断点时,如何main
再次first
进入堆栈?
很长一段时间以来,如果您在调试器中运行代码,简单的答案是它们不会。您只需获得您所在的函数,调试器就会告诉您它是从“异步代码”或类似代码中调用的。
然而,现在一些调试器可以跟随等待的代码回到它正在解决的承诺(请记住,await
并且async
大部分只是承诺之上的语法糖)。换句话说,当您等待的代码完成并且引擎盖下的“承诺”得到解决时,您的调试器有助于确定堆栈“应该”是什么样子。它显示的内容实际上与引擎最终调用该函数的方式并无太大相似之处——毕竟,它是在事件循环之外调用的。但是,我认为这是一个有用的补充,使我们所有人都能够保持代码的思维模型比实际发生的要简单得多!
一些关于它是如何工作的进一步阅读,其中包含比我在这里更多的细节:
推荐阅读
- javascript - 代码重构。试图改进我的代码
- python-3.x - Python 硒火狐使用 .click() 选择
- python - 用一个简单的语句制作两个条件/循环语句在一条 python 行中工作
- makefile - 试图理解为什么 make 失败
- mysql - 通过 vsts 调用表达式返回以代码“1”退出
- amazon-web-services - 将云端请求重定向到新 URL
- angular - PrimeNg 饼图 - 默认显示所有工具提示?
- android - 在 Room 中链 2 @Query 命令
- javascript - 当我单击按钮时,我不知道出了什么问题
- javascript - 我正在实施一个项目,我必须接受所有 url 请求