【问题标题】:Await keyword in Javascript async function is not waiting for promises to complete in sequential orderJavascript异步函数中的等待关键字不等待承诺按顺序完成
【发布时间】:2021-12-05 13:49:41
【问题描述】:

我是 Javascript 新手,正在尝试学习 Promise 和 async/await 概念。我创建了三个 promise,如下所示。

const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log("promise1");
        resolve("1");
    }, 1000)

});

const promise2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log("promise2");
        resolve("2");
    }, 5000)

});

const promise3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log("promise3");
        resolve("3");
    }, 4000)

});

我创建了一个异步函数,它按顺序使用 await 来处理多个 Promise,如下所示。


async function example() {


    const result1 = await promise1;
    const result2 = await promise2;
    const result3 = await promise3;
    console.log(result1);
    console.log(result2);
    console.log(result3);
}

example();

浏览器控制台的输出是-

promise1
promise3
promise2
1
2
3

我不明白为什么在我的输出中 promise3 出现在 promise2 之前,因为在异步函数示例中的 await 语句序列中,promise2 出现在 promise3 之前?根据我的说法,输出应该如下所示 -

promise1
promise2
promise3
1
2
3

如果我遗漏了什么或有任何错误,请纠正我。

【问题讨论】:

  • 那是因为awaits 等待。
  • await 关键字不会“解决”或“执行”或“运行”承诺。它只等它安定下来。解决 promise 的异步任务在此之前已经开始,通常是在构建 promise 时。

标签: javascript asynchronous async-await promise


【解决方案1】:
const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log("promise1");
        resolve("1");
    }, 1000)
});

当你构造一个 Promise 时,它​​里面的代码会立即运行。因此,一旦这条线完成,计时器就会关闭并运行。您的代码预先创建了其中的 3 个承诺,这意味着它预先启动了所有 3 个计时器。

稍后当您await 承诺时,这不会改变计时器正在做的事情。它只是让您的async 函数知道它们何时完成。所以在后台,计时器将开始关闭,将事情记录下来,并解决他们相应的承诺。即使没有任何东西在等待承诺,这也可能发生。 1000 毫秒的超时将是第一个超时,3 秒后是 4000 毫秒的超时,然后 1 秒后是 5000 毫秒的超时

如果您希望计时器仅在您到达异步函数的那一行时才启动,那么您需要在异步函数的那一行执行 setTimeouts。例如:

async function example() {
  const result1 = await new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("promise1");
      resolve("1");
    }, 1000);
  });
  const result2 = await new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("promise2");
      resolve("2");
    }, 5000);
  });
  const result3 = await new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("promise3");
      resolve("3");
    }, 4000);
  });
  console.log(result1);
  console.log(result2);
  console.log(result3);
}

【讨论】:

    【解决方案2】:

    简而言之,这是因为您首先创建了这三个 Promise,并且在创建这三个 Promise 的过程中,您还启动了您的三个计时器。这三个计时器都已启动,并且都在并行运行。

    然后,您可以使用await promise1。但是,该语句与计时器何时调用其回调完全无关。他们将完全靠自己来做到这一点。因此,计时器回调本身会根据每个计时器设置的预期时间创建console.log() 输出(与您拥有的await 无关)。

    所以,之所以会这样,是因为您首先创建了所有三个 Promise 和计时器,然后才执行await。这里要理解的重要一点是“承诺不会执行”。它们本身不是异步操作。只要您执行new Promise(),它就会调用promise executor 函数并启动您在其中的异步操作。从那时起,Promise 所做的就是监视该异步操作,然后在该异步操作完成时通知观察者。

    如果您添加每个计时器启动时的日志记录,您可以查看有关事情顺序的更多详细信息,这将显示所有三个计时器最初都已启动并并行运行,并且可以调用它们的计时器回调完全独立于代码后面的 await 语句:

    const promise1 = new Promise((resolve, reject) => {
        console.log("starting timer 1");
        setTimeout(() => {
            console.log("promise1");
            resolve("1");
        }, 1000)
    
    });
    
    const promise2 = new Promise((resolve, reject) => {
        console.log("starting timer 2");
        setTimeout(() => {
            console.log("promise2");
            resolve("2");
        }, 5000)
    
    });
    
    const promise3 = new Promise((resolve, reject) => {
        console.log("starting timer 3");
        setTimeout(() => {
            console.log("promise3");
            resolve("3");
        }, 4000)
    
    });
    
    async function example() {
        const result1 = await promise1;
        const result2 = await promise2;
        const result3 = await promise3;
        console.log(result1);
        console.log(result2);
        console.log(result3);
    }
    
    example();

    如果您更改了代码的结构,以便您等待的函数是实际创建和启动计时器的函数,那么在第一个计时器触发并且您将拥有顺序计时器之前,您不会启动第二个计时器.

    因此,如果您这样做,您的预期输出将会发生:

    function runTimer1() {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log("promise1");
                resolve("1");
            }, 1000)
    
        });
    }
    
    function runTimer2() {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log("promise2");
                resolve("2");
            }, 5000)
    
        });
    }
    
    function runTimer3() {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log("promise3");
                resolve("3");
            }, 4000)
    
        });
    }
    
    async function example() {
        const result1 = await runTimer1();
        const result2 = await runTimer2();
        const result3 = await runTimer3();
        console.log(result1);
        console.log(result2);
        console.log(result3);
    }
    
    example();

    【讨论】:

      【解决方案3】:

      那是因为您在 async 函数之外创建 Promise 而不等待。 Promise 中的回调是 syncrounos。您一个接一个地运行 3 setTimeout。示例:

      const x = new Promise(resolve => console.log(1))
      console.log(2)
      

      这会注销 1,2 - 而不是异步回调 ex。在 setTimeout 中:

      setTimeout(() => console.log(1));
      console.log(2)
      

      这会注销 2,1。

      因此,如果您想要正确的行为,则必须在等待 Promise 时创建它们,这是常见的做法:

      function makePromise(time, number) {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            console.log("promise", number);
            resolve(number);
          }, time);
        });
      }
      
      
      async function example() {
          const result1 = await makePromise(1000, 1);
          const result2 = await makePromise(5000, 2);
          const result3 = await makePromise(4000, 3);
          console.log(result1);
          console.log(result2);
          console.log(result3);
      }
      
      example();
      

      【讨论】:

        猜你喜欢
        • 2018-03-05
        • 2018-02-03
        • 2020-11-19
        • 2019-06-16
        • 1970-01-01
        • 1970-01-01
        • 2018-04-17
        • 1970-01-01
        • 2017-06-15
        相关资源
        最近更新 更多