如果我声明如下函数:
function a(){
//do something
}
如果我用a()
执行它,它将放到调用堆栈的顶部,并在完成时弹出。当函数在调用堆栈中时,主线程被阻塞,无法执行其他操作,直到调用堆栈为空。
但是使用async
函数到底会发生什么?
如果我这样做:
async function b() {
//do something
}
该函数返回一个promise,并且不阻塞主线程。这是否意味着该函数传递给Web API而不是调用栈?然后将其传递给回调que,然后传递给callstack,以便我们可以执行回调函数?
b.then(function() {
//do something after finish
})
答案 0 :(得分:2)
是的,async function
将在执行期间像正常函数一样位于调用堆栈中。您可以考虑停用await
关键字:
function log(x) {
console.log("at "+x);
}
function delay(t) {
return new Promise(resolve => setTimeout(resolve, t));
}
async function example() {
log(1);
await delay(50);
log(2);
return 3;
}
function example2() {
log(1);
return delay(50).then(function cont() {
log(2);
return 3;
})
}
example()
呼叫的工作原理与example2()
呼叫完全相同。被调用的函数被推入堆栈,调用log(1)
,它被推入堆栈并运行,当返回(从堆栈弹出)时,它调用delay(50)
,它被放到堆栈并运行,等等。现在,当对await
运算符求值时,异步函数将采用操作数承诺,使用.then()
调用附加回调,然后从example()
调用中返回 对功能主体最终完成的承诺。因此,当它到达await
关键字时,它会从堆栈中弹出,并且调用方可能会继续运行同步代码(这通常涉及对返回的promise进行操作)。
然后,在解决了诺言(在上面的示例中,当超时)时,安排了作业运行附加的then
回调。他们可能必须等待事件循环变为空闲状态(调用堆栈为空),然后当promise作业启动时,代码再次被放入调用堆栈中。在example2
中,将调用此cont
函数,在async function
中,它将是example
主体的延续,在{{1 }}。在这两种情况下,它都调用await
并将其推入堆栈并运行,并在返回时(从堆栈中弹出)执行log(2)
语句,该语句将解析promise,并从中弹出执行上下文堆栈,将其留空。
答案 1 :(得分:0)
它确实进入了调用栈,当它运行异步函数的时间移出调用栈,直到该函数实现或被拒绝。此时,它将移入回调队列,而所有其他同步函数可以继续在调用堆栈之外执行,然后在调用堆栈为空时,事件循环在回调队列中查找是否需要执行其他任何操作。如果回调队列中有任何内容,则事件循环会将回调推入调用堆栈以执行。