【问题标题】:Async / await vs then which is the best for performance?Async / await vs then 哪个最适合性能?
【发布时间】:2019-06-26 23:42:14
【问题描述】:

我在 JavaScript 中有一个简单的代码,它在 API 中执行请求并返回响应,很简单。但在这种情况下,我将有数千个请求。那么,哪一个代码选项会执行得更好,以及为什么。还有哪一个被推荐为这些天的好习惯?

第一个选项是使用 .then 来解决承诺,第二个选项是使用 async / await。

在我的测试中,这两个选项的结果非常相似,没有显着差异,但我不确定规模。

// Using then
doSomething(payload) {
  const url = 'https://link-here/consultas';
  return this.axios.get(url, {
    params: {
      token: payload.token,
      chave: payload.chave,
    },
   }).then(resp => resp.data);
}

// Using Async / await
async doSomething(payload) {
   const url = 'https://link-here/consultas';
   const resp = await this.axios.get(url, {
   params: {
     token: payload.token,
     chave: payload.chave,
    },
 });
 return resp.data;
}

任何解释都会很有价值。

【问题讨论】:

  • 您好!看看blog.pusher.com/promises-async-await。并且不要忘记用 try/catch 块包装你的 async/await 代码。
  • 性能差异不应该是真正值得烦恼的事情:无论如何,http 请求肯定会占用 >99% 的执行时间。如果您可以并行启动几个请求,并通过Promise.all 加入他们的响应,则可以获得真正的收益。然后启动下一批,...等等。
  • 我不确定这是否可以在这里应用,但请参阅来自 V8 开发人员的一般建议 at the end of this article:“赞成 async 函数和 await 而不是手写的承诺代码”。
  • @NikolayVetrov - 没有理由将await 包装在try/catch 中。 OP 只想返回被拒绝的承诺,async 函数将捕获拒绝并自动执行此操作。在比这更复杂的错误处理情况下,try/catch 将是必需的和有用的。

标签: javascript node.js async-await


【解决方案1】:

await 只是.then() 的内部版本(基本上做同样的事情)。选择其中一个的原因实际上与性能无关,而是与所需的编码风格或编码方便性有关。当然,解释器内部有a few more opportunities to optimize thingsawait,但这不太可能是您决定使用哪个的方式。如果其他条件相同,我会选择await,原因如上所述。但是,我会首先选择哪个使代码更易于编写、理解、维护和测试。

使用得当,await 经常可以save you a bunch of lines of code making your code simpler to read, test and maintain。这就是它被发明的原因。

您的代码的两个版本之间没有有意义的区别。当 axios 调用成功或出错时,两者都达到相同的结果。

如果您有多个需要序列化的连续异步调用,await 可以带来更多便利的不同之处。然后,与其将它们分别放在 .then() 处理程序中以正确链接它们,不如使用 await 并拥有更简单的代码。

await.then() 的一个常见错误是忘记正确的错误处理。如果您在此函数中的错误处理愿望只是返回被拒绝的承诺,那么您的两个版本都会这样做。但是,如果您连续有多个异步调用,并且您想要执行比仅返回第一个拒绝更复杂的操作,那么 error handling techniques for await and .then()/.catch() 就完全不同了,这似乎更简单取决于具体情况。

【讨论】:

  • 对。使用'await'的另一个好处是功能明确标记
【解决方案2】:

这个帖子应该有一些更正。 await.then 会给出非常不同的结果,并且应该用于不同的原因。

await 将等待某事,然后继续下一行。它也是两者中更简单的一个,因为它的机械行为更像是同步行为。您执行第 1 步,等待,然后继续。

console.log("Runs first.");
await SomeFunction();
console.log("Runs last.");

.then 从原始调用中分离出来并开始在自己的范围内运行,并将在原始范围无法预测的时间进行更新。如果我们可以暂时搁置语义,它会“更加异步”,因为它会离开旧范围并分支到新范围。

console.log("Runs first.");
SomeFunction().then((value) => {console.log("Runs last (probably). Didn't use await on SomeFunction().")})
console.log("Runs second (probably).");

【讨论】:

  • 为什么 await/.then 会给出不同的结果。它们旨在使用不同的语法来做同样的事情。其次,await 在技术上并不是阻塞行为,因为它不会阻塞线程。而且我不会将.then 描述为“更异步”。它们都是异步的,我认为这样考虑没有帮助。
  • 请在您的回答中提供更多详细信息。正如目前所写的那样,很难理解您的解决方案。
  • 我添加了一些清晰度来说明我的意思。这是两个非常不同的功能。显然更多的讨论涉及到异步,它属于完整指南,我清楚地在声明前加上“如果我们把语义放在一边。”
【解决方案3】:

其实。 Await/Async 可以更有效地执行,因为 Promise.then() 在执行后失去了调用它的范围,您正在将回调附加到回调堆栈。

它的原因是:系统现在必须存储对调用 .then() 的位置的引用。如果出现错误,它必须正确指向错误发生的位置,否则,如果没有范围(因为系统在调用 Promise 后恢复执行,等待稍后返回 .then())它无法指向发生错误的地方。

Async/Await 暂停执行被调用的方法,从而保留引用。

【讨论】:

    【解决方案4】:

    作为对@user280209 答案的更多解释,让我们考虑以下函数,它返回承诺并将其执行与.then()async await 进行比较。

    function call(timeout) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log(`This call took ${timeout} seconds`);
          resolve(true);
        }, timeout * 1000);
      });
    }
    

    .then()

    (async () => {
      call(5).then((r) => {
        console.log(r);
      });
      await call(2); //This will print result first
      await call(1);
    })();
    

    当运行上述调用时,日志将是

    This call took 2 seconds
    This call took 1 seconds
    This call took 5 seconds
    true
    

    正如我们所见,.then() 在完成之前不会暂停其下一行的执行。

    async/wait

    (async () => {
      await call(5); //This will print result first
      await call(2); 
      await call(1);
    })();
    

    当运行上述函数日志将是

    This call took 5 seconds
    This call took 2 seconds
    This call took 1 seconds
    

    所以我认为如果你的 promise 的结果不会用在下面的行中,.then() 可能会更好。

    【讨论】:

    • 感谢您提供的示例!在第一个call(5).then 上,它会在您等待await call(2)await call(1) 时在后台继续执行吗?
    【解决方案5】:

    对于那些说 await 在异步调用返回之前阻塞代码的人来说,你没有抓住重点。 “await” 是 promise.then() 的语法糖。它有效地将函数的其余部分包装在它为您创建的 promise 的 then 块中。没有真正的“阻塞”或“等待”。

    run();
    
    async function run() {
        console.log('running');
        makePromises();
        console.log('exiting right away!');
    }
    
    async function makePromises() {
        console.log('make promise 1');
        const myPromise = promiseMe(1)
        .then(msg => {
            console.log(`What i want to run after the promise is resolved ${msg}`)
        })
        console.log('make promise 2')
        const msg = await promiseMe(2);
        console.log(`What i want to run after the promise is resolved via await ${msg}`)
    }   
    
    function promiseMe(num: number): Promise<string> {
        return new Promise((resolve, reject) => {
            console.log(`promise`)
            resolve(`hello promise ${num}`);
        })
    }
    

    makePromises 中的 await 行没有阻塞任何东西,输出为:

    • 正在运行
    • 承诺 1
    • 承诺
    • 承诺 2
    • 承诺
    • 马上退出!
    • promise 解决后我要运行的内容 hello promise 1
    • 通过 await hello promise 2 解决 promise 后我想要运行的内容

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-05
      • 2020-09-21
      • 2013-11-25
      • 1970-01-01
      • 2018-10-09
      相关资源
      最近更新 更多