为什么我的async/await函数异常?(Javascript)

3

这是我的Javascript代码。我认为结果是1 2 3 4 5。

async function fn1 () {
    console.log(1);
    await fn2();
    console.log(3);
};

async function fn2 () {
    console.log(2);
};

fn1();
new Promise((resolve, reject) => {
    console.log(4)
    resolve()
}).then(() => {
    console.log(5)
})

But. The results are: 1 2 4 5 3.


似乎console.log(3)在下一个tick中。 - Xu Young
1
为什么数字“3”应该在数字“4”之前发生? - Juffy
我们使用async/await来解决异步问题。 - Xu Young
4个回答

5

// functions declaration

async function fn1 () {
    console.log(1);
    await fn2(); // wait for async function fn2(which gets dispatched on thread 3) => so console.log(2) should be here chronologically
    console.log(3);
};

async function fn2 () {
    console.log(2);
};


// thread 1 starts (the actual execution code)

fn1(); // since fn1 is async it gets dispatched on thread 2

new Promise((resolve, reject) => {
    console.log(4)
    resolve() // trigger () => {console.log(5)}
}) // promise declaration
.then(() => {
    console.log(5)
}) // execute the promise right away

简单来说,console.log(1)console.log(2)console.log(3)按照时间顺序在一个线程上执行,console.log(4)console.log(5)按照时间顺序在另一个线程上执行。它们彼此交错。
附注:JavaScript本身是单线程的,不支持多线程!(除了Web Worker等,在我们讨论“异步”时)我这里简化了很多,并使用术语“线程”,只是为了易于理解。为了不误导您关于异步操作的概念,如果您不确定JavaScript中异步操作的工作原理,建议您阅读这篇问答

异步函数 init() { // 与上面的代码相同 // 但是等待 fn1() }init()如果我使用一个函数来调用它们,我的结果是 1 2 3 4 5。为什么会这样? - Xu Young
@XuYoung 这是因为您正在等待执行 fn1() 后再对 Promise 进行任何操作。 - viz
@XuYoung 我编辑了我的评论。如果你在修改之前看到了之前的评论,我很抱歉造成了混淆。await 只能在 async 函数中使用。 - viz
无论如何,如果您执行 async function init () { // codes same as above // but await fn1() } init(),线程1将等待fn1()(已分派到线程2)完成,这使得console.log(1) // in thread 2 console.log(2) // in thread 3 console.log(3) // in thread 2 console.log(4); console.log(5); // in thread 1按照时间顺序执行。 - viz
谢谢。你太棒了! - Xu Young

0
问题是JS代码本质上是异步的。因此,在执行打印'3'之前,它已经触发了其他指令,并且这些指令在那个结束之前就已经完成了。

0
上面的 fn1() 和 new Promise() 的执行是异步的,这就是为什么指令的顺序是独立的。如果你想要得到你想要的结果,可以尝试下面的代码:
async function fn1 () {
    console.log(1);
    await fn2();
    console.log(3);
};

async function fn2 () {
    console.log(2);
};

async function makeExectionOrder(){ // move the blocks into asynch function
    await fn1(); // make synchrounous call
    new Promise((resolve, reject) => {
        console.log(4)
        resolve()
    }).then(() => {
        console.log(5)
    })

}

makeExectionOrder()

谢谢您的回复。我想再深入思考一下。async声明的功能是在微任务中吗? - Xu Young
你可以这样做:fn1().then(()=>new Promise...console.log(4)... - HMR
谢谢,这很有帮助。 - Nic Olas

0

你必须理解栈和队列:

更多信息:栈和队列视频文档

当你执行new Promise(fnResolvingOrRejecting)时,函数fnResolvingOrRejecting会立即被调用,因此它在同一个栈上。还没有排队任何东西。

如果你理解了什么是栈和队列,你可以更好地解释你的代码,省略混淆的异步和等待语法。

一旦你理解了它实际上做了什么,语法确实会改善代码,但在这种情况下,我会将其省略,以便你可以看到哪些代码作为回调/结果处理程序执行,哪些代码在栈上。

function fn1 () {
  console.log(1);//on the same stack as calling fn1
  fn2()//executing fn2
  .then(//first queued
    () => console.log(3)
  );
};

function fn2 () {
  return new Promise(
    (resolve)=>{
      console.log(2);//on the same stack as calling fn1
      resolve();
    }
  );
};

fn1();//calling fn1 immediatly logs 1 and 2 because they are on the same stack
new Promise((resolve, reject) => {
  //after calling fn1 and queing console.log(3) this is executed because it's on
  //  the same stack
  console.log(4)
  resolve()
}).then(() => {//second queued
  console.log(5)
})

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