【问题标题】:Why my async/await function is abnormal?(Javascript)为什么我的 async/await 函数异常?(Javascript)
【发布时间】:2018-07-10 02:59:43
【问题描述】:

这是我的 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)
})

但是。结果是:1 2 4 5 3。

【问题讨论】:

  • console.log(3) 似乎在下一个滴答声中。
  • 为什么 '3' 应该出现在 '4' 之前?
  • 我们使用 async/await 是为了解决异步问题。

标签: javascript


【解决方案1】:

// 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 等,在我们的“异步”上下文中)我简化了很多并使用了术语thread 在这里只是为了便于理解。为了不在异步操作的概念上误导您,如果您不确定 JavaScript 中的异步是如何工作的,我建议您阅读 QnA

【讨论】:

  • async function init () { // 代码与上面相同 // 但是等待 fn1() } init() 如果我使用函数调用这些,我的结果是 1 2 3 4 5. 为什么是吗?
  • @XuYoung 这仅仅是因为你在等待fn1() 被执行,然后你才对Promise 做任何事情。
  • @XuYoung 我编辑了我的评论。如果您在编辑之前看过前一个,我会感到困惑。 await 仅在 async 函数中有效。
  • 所以无论如何,如果你执行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 @987654337 @console.log(4); console.log(5); // in thread 1 按时间顺序执行。
  • 谢谢。你太棒了!
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    上面的 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()
    

    【讨论】:

    • 感谢您的回复。我想再深入一点。微任务中异步声明的作用是什么?
    • 你可以这样做fn1().then(()=>new Promise...console.log(4)...
    • 谢谢,很有帮助。
    【解决方案4】:

    你必须了解堆栈和队列:

    更多信息:堆栈和队列videoducumentation

    当您执行new Promise(fnResolvingOrRejecting) 时,会立即调用函数fnResolvingOrRejecting,因此它位于同一个堆栈上。尚未排队。

    如果您了解堆栈和队列是什么,您可以更好地解释您的代码,从而省略令人困惑的 async 和 await 语法。

    一旦你理解了它的实际作用,语法就会真正改进代码,但在这种情况下,我将把它省略,这样你就可以看到哪些代码作为回调/结果处理程序执行,哪些代码在堆栈上。

    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)
    })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-26
      • 2019-04-05
      • 2019-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多