异步功能是否已添加到调用堆栈?

时间:2020-07-01 09:27:50

标签: javascript asynchronous async-await

如果我声明如下函数:

function a(){
   //do something
}

如果我用a()执行它,它将放到调用堆栈的顶部,并在完成时弹出。当函数在调用堆栈中时,主线程被阻塞,无法执行其他操作,直到调用堆栈为空。 但是使用async函数到底会发生什么?

如果我这样做:

async function b() {
   //do something
}

该函数返回一个promise,并且不阻塞主线程。这是否意味着该函数传递给Web API而不是调用栈?然后将其传递给回调que,然后传递给callstack,以便我们可以执行回调函数?

b.then(function() {
   //do something after finish
})

2 个答案:

答案 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)

它确实进入了调用栈,当它运行异步函数的时间移出调用栈,直到该函数实现或被拒绝。此时,它将移入回调队列,而所有其他同步函数可以继续在调用堆栈之外执行,然后在调用堆栈为空时,事件循环在回调队列中查找是否需要执行其他任何操作。如果回调队列中有任何内容,则事件循环会将回调推入调用堆栈以执行。