【问题标题】:Why does this JavaScript async/await code not behave as expected?为什么这个 JavaScript async/await 代码没有按预期运行?
【发布时间】:2017-12-13 14:54:37
【问题描述】:

我已尝试阅读异步/等待的指南和教程,但我似乎无法在任何地方找到此问题。

这里是有问题的代码:

    var func1 = new Promise((resolve, reject) => {
      console.log("Func1");
      setTimeout(() => {
        resolve(10);
      }, 100);
    });
    
    var func2 = new Promise((resolve, reject) => {
      console.log("Func2");
      setTimeout(() => {
        resolve(20);
      }, 5000);
    })
    
    let run = async() => {
      let var1 = await func1;
      let var2 = await func2;
      console.log(var1);
      console.log(var2);
    }

    run();

我们看到“Func1”和“Func2”被立即打印,一个接一个。 5 秒后,在 func2 中指定的超时,我们打印出“10”和“20”。到目前为止一切顺利。

但是如果我把最后一段代码改成这样:

let run = async() => {
  let var1 = await func1;
  console.log(var1);
  let var2 = await func2;
  console.log(var2);
}

然后我看到“Func1”立即打印出来,但“Func2”也打印出来了,尽管 console.log(var1) 出现在它之前。 100ms 后出现“10”,5 秒后出现“20”。

来自 MDN:

await 表达式会导致异步函数执行暂停,直到 Promise 被履行或拒绝,并在履行后恢复异步函数的执行。

但这似乎不是正在发生的事情。如果是,我们不会看到“Func1”,然后是“10”,然后 func2 被执行,因此打印“Func2”,5 秒后我们得到“20”? func1 应该被执行,一旦它被解决(在 100 毫秒内),console.log(var1) 应该被触发。我在这里错过了什么?

【问题讨论】:

标签: javascript asynchronous async-await


【解决方案1】:

这样做的原因是您之前已经运行过您的承诺执行程序。 Promise 执行器在传递给 Promise 构造函数时会立即进行评估,因此您将获得以下信息:

var func1 = new Promise((resolve, reject) => ...); // Logs "Func1"
var func2 = new Promise((resolve, reject) => ...); // Logs "Func2"

let run = async() => {
  let var1 = await func1;
  console.log(var1); // Logs 10
  let var2 = await func2;
  console.log(var2); // Logs 20
}

run();

【讨论】:

    【解决方案2】:

    这里的主要问题是func1func2 不是函数;它们是承诺。正如 Jonas W. 所说,promise 会立即调用它们的回调 (resolve, reject) =>,等待它们只会让它们等待直到它们被解决。

    你可以在这里看到你想要的结果:

    var func1 = () => {
       return new Promise((resolve, reject) => {
        console.log("Func1");
        setTimeout(() => {
          resolve(10);
        }, 100);
      });
    }
            
    var func2 = () => {
      return new Promise((resolve, reject) => {
        console.log("Func2");
        setTimeout(() => {
          resolve(20);
        }, 5000);
      });
    }
            
    let run = async() => {
      let var1 = await func1();
      let var2 = await func2();
      console.log(var1);
      console.log(var2);
    }
    
    run();

    【讨论】:

    • 最好不要谈论承诺“开始”任何事情。 timeouts 是立即开始的,promise 只会被创建(它们将在稍后得到解决)。
    • @Bergi 立即调用传递给 Promise 的函数,以尝试解决它。 Promise 类本质上是通过触发提供给构造函数的回调来开始解析。
    • 是的,promise constructor 启动了 executor 回调,因此该进程将在 promise 的解析中结束(请注意,在调用 resolve 之前它不会解析任何内容)。然而很多人认为promise instance 可以在空闲时(甚至多次)启动任务,这显然是错误的。
    【解决方案3】:

    await 基本上意味着在继续之前确保以下值可用。承诺在您创建时开始解决,等待它的时间无关紧要。

    【讨论】:

      【解决方案4】:

      run 函数是同步顺序的,例如代码一步一步来:

      1. 调用 func1() 并等待回复。
      2. 调用 func2() 并等待回复。
      3. 记录 var1。
      4. 记录 var2。

      所以最后两个步骤只会在对 func2() 的调用完成时运行,例如超时后的数据。因此它将等待整整 5 秒,直到同时记录 var1 和 var2。

      另一种方式则完全不同 1. 调用 func1() 并等待直到有回复。 2. 记录 var1。 3. 调用 func2() 并等待直到有回复。 4. 记录 var2。

      第 2 步将等到第 1 步返回数据,例如在 100 毫秒之后,然后将继续对第 3 步和第 4 步执行相同操作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-12-04
        • 1970-01-01
        • 2018-07-20
        • 2019-09-21
        • 1970-01-01
        • 1970-01-01
        • 2021-12-11
        相关资源
        最近更新 更多