执行上下文:为什么这段JavaScript代码会表现出这样的行为?

4

我已开始学习JavaScript中的异步编程。请查看下面的代码:

const myPromise = () => Promise.resolve('I have resolved');

function firstFunction() {
  myPromise().then(res => console.log(res));
  console.log('firstFunction');
}

async function secondFunction() {
  console.log(await myPromise());
  console.log('secondFunction');
}

firstFunction()
secondFunction();

这段代码将输出以下内容:
  • firstFunction
  • I have resolved
  • I have resolved
  • secondFunction

我对这个输出很满意,我认为我也理解了这其中的原因:

  • FirstFunction() 进入调用栈
  • 承诺会被放在事件循环中暂停执行
  • console.log('firstFunction') 运行并打印 (firstFunction)
  • 现在调用栈为空,因此已解决的承诺将被打印 (I have resolved)
  • 接下来 SecondFunction() 进入调用栈
  • 由于我们使用了 Async await,该代码将等待 myPromise()
  • 然后将打印 (I have resolved)
  • 最后它将打印 (secondFunction)

当我将上述代码更改为以下方式时:

const myPromise = () => Promise.resolve('I have resolved');

function sayHi() {
  console.log('hi');
}

function firstFunction() {
  myPromise().then(res => console.log(res));
  console.log('firstFunction');
}

async function secondFunction() {
  console.log(await myPromise());
  console.log('secondFunction');
}

firstFunction()
secondFunction();
sayHi();

我期望代码的输出如下:
  • firstFunction
  • 我已经解决了
  • 我已经解决了
  • secondFunction
  • hi
但实际上代码的输出为:
  • firstFunction
  • hi
  • 我已经解决了
  • 我已经解决了
  • secondFunction
请问这段代码的行为可以解释一下吗?

1
我认为你的问题可以简化为 -> 为什么Hi不是最后显示。答案是因为在你的代码中没有任何指示等待firstFunctionsecondFunction完成,就这么简单。 - Keith
现在调用栈为空,这就是你的错误。 firstFunctionsecondFunction 都是匿名框架的一部分,需要完成后才能开始事件循环的下一个迭代。 - Ivar
这就是我所缺失的部分:firstFunction和secondFunction都是匿名框架的一部分,需要在事件循环的下一次迭代开始之前完成。感谢Ivar的澄清。 - Andrea MeAndy Fiorucci
3个回答

1
为了让消息队列执行存储的消息(来自异步函数),调用堆栈需要为空。您可以查看这篇关于事件循环的文章,以说明这种行为。在第二种情况下,调用堆栈有3个需要执行并从中删除的函数,在消息队列中的消息得到执行之前,因此必须在异步调用之前打印hi。由于secondFunction位于异步函数内部,并且在其前面有一个等待,因此最后执行它。

0

想象以下所给出的数字:

1 - firstFunction()

2 - secondFunction();

3 - sayHi();

Hi 在列表中排名第二,这是因为达到数字3比解决承诺更快。由于数字1中的console.log()不在承诺中,它立即执行,并在hi消息之前发生。

1、2和3都被执行,但是因为1和2中的承诺值花费了x毫秒来解决,所以在任何基于承诺的控制台日志之前打印Hi。


0

带有注释的:

function firstFunction() {
  myPromise().then(res => console.log(res)); // this console.log will be called 
                                             //after myPromise() is _resolved_
  console.log('firstFunction');              // this console.log will be called 
                                             // after function myPromise() is _called_
}

async function secondFunction() {
  console.log(await myPromise()); // again, not gonna console.log until myPromise()
                                  // is resolved...
  console.log('secondFunction');  // and any subsequent line isn't going to be executed
                                  // until `await` is complete
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接