【问题标题】:Difference of using async / await vs promises?使用异步/等待与承诺的区别?
【发布时间】:2019-04-03 01:41:09
【问题描述】:

我正在寻找关于在我的 nodeJS 应用程序中使用什么的答案。

我有处理我对 mssql 的通用 dB 访问的代码。这段代码是使用 async 函数编写的,然后我使用 promise 调用该函数并且一切正常。

随着我的应用程序越来越大,代码越来越大,我计划将一些逻辑移动到函数中,然后调用它们。

所以我的问题是:混合使用 async/await 和 Promise 有什么缺点,还是真的没关系?

Async / await 使编写更具可读性的代码变得更容易,因为我必须在返回某些内容之前读取和写入多个数据库,并且我需要其中一些结果。

那么问题是什么是更好的方法? 已设置且无法更改的 dB 层上的异步/等待 逻辑层 async / await 这将允许我在函数调用上进行 async / 和 await ,或者如果我对逻辑使用 promise,那么我在函数调用时会被 promise 卡住。

所以我希望有人能给我更多的见解,如果一个人比另一个人有更多的优势,除了能够编写更清晰的代码。

【问题讨论】:

  • 这篇文章强调了 async/await 相对于 promises 的一些优势...hackernoon.com/… - 但我很想知道使用一种方法是否有任何性能改进...
  • @Alqbal 与 async/await 相比没有性能改进。
  • async/await 仅适用于承诺,因此没有async/await OR 承诺,只有async/await AND 承诺。所以,你真的是在问你是只使用简单的承诺还是使用 async/await 的承诺。
  • 我们可以清理一些重要的东西吗? async / await 都是关于承诺的,所以这个问题的措辞是误导性的。 await 语句等待承诺被履行。您真正要问的是使用 awaitthen() 方法。简短的回答是,这主要是品味问题,因为他们做同样的工作。

标签: javascript node.js promise async-await


【解决方案1】:

async/await 和 promises 密切相关。 async 函数返回承诺,await 是等待承诺解决的语法糖。

混合使用 Promise 和 async 函数的唯一缺点可能是代码的可读性和可维护性,但您当然可以将异步函数的返回值用作 Promise,以及将 await 用于返回的常规函数一个承诺。

您是否选择其中一个主要取决于可用性(您的 node.js / 浏览器是否支持async?)和您的审美偏好,但一个好的经验法则(基于我当时的偏好写作)可能是:

如果需要串行运行异步代码:考虑使用async/await

return asyncFunction()
.then(result => f1(result))
.then(result2 => f2(result2));

const result = await asyncFunction();
const result2 = await f1(result);
return await f2(result2);

如果你需要嵌套的 Promise:使用 async/await:

return asyncFunction()
.then(result => {
  return f1(result)
  .then(result2 => f2(result, result2);
})

const result = await asyncFunction();
const result2 = await f1(result);
return await f2(result, result2);

如果您需要并行运行:使用 Promise。

return Promise.all(arrayOfIDs.map(id => asyncFn(id)))

建议您可以在表达式中使用await 来等待多个任务,如下所示:
*注意,这仍然是从左到右依次等待,如果您不这样做也可以期待错误。否则,由于fail fast behaviourPromise.all() 导致行为不同

const [r1, r2, r3] = [await task1, await task2, await task3];

(async function() {
  function t1(t) {
    console.time(`task ${t}`);
    console.log(`start task ${t}`);
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        console.timeEnd(`task ${t}`);
        resolve();
      }, t);
    })
  }

  console.log('Create Promises');
  const task1 = t1(100);
  const task2 = t1(200);
  const task3 = t1(10);

  console.log('Await for each task');
  const [r1, r2, r3] = [await task1, await task2, await task3];

  console.log('Done');
}())

但与Promise.all 一样,并行promise 需要在出现错误时得到妥善处理。你可以阅读更多关于here的信息。

注意不要将前面的代码与以下代码混淆:

let [r1, r2] = [await t1(100), await t2(200)];

function t1(t) {
  console.time(`task ${t}`);
  console.log(`start task ${t}`);
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.timeEnd(`task ${t}`);
      resolve();
    }, t);
  })
}
console.log('Promise');
Promise.all([t1(100), t1(200), t1(10)]).then(async() => {

  console.log('Await');
  let [r1, r2, r3] = [await t1(100), await t1(200), await t1(10)]
});

使用这两种方法是不等价的。 Read more about the difference.

最后,Promise.all 是一种更简洁的方法,可以更好地扩展到任意数量的任务。

【讨论】:

  • 实际上你可以使用 await let [r1, r2] = [await task1, await task2] 并行运行。看stackoverflow.com/questions/35612428/…
  • @Qwerty 感谢您的反馈!我不确定这是否正确。检查我的编辑和链接的答案。那有意义吗?如果我弄错了,请告诉我!
  • @lucascaro 我有疑问。与使用 then 相比,await 不会使代码阻塞吗?
  • 某种意义上,你可以这么想,await“暂停”当前函数,直到 promise 被解决,但是由于这个函数是异步的,它不会阻塞任何外部的当前函数。
  • 您的代码没有反映@Qwerty 的建议(如果您点击链接会更清楚)。 task1task2 是 Promise,因此它们已经在并行运行。在使用await 之前,您需要先调用每个t1(),而不是[await t1(100), await t1(200), await t1(10)]。一个冗长的方式是let task1 = t1(100); let task2 = t1(200); let task3 = t1(10); let [r1, r2, r3] = [await task1, await task2, await task3];。但是在 async/await 代码中使用 Promise.all 是有意义的,因为 await 只需要 Promise: let [r1, r2, r3] = await Promise.all([t1(100), t1(200), t1(10)]);
【解决方案2】:

其实这取决于你的节点版本,但如果你可以使用async/await,那么你的代码将更具可读性和更易于维护。 当您将函数定义为“异步”时,它会返回本机 Promise,当您使用 await 调用它时,它会执行 Promise.then。

注意: 将您的 await 调用放在 try/catch 中,因为如果 Promise 失败,它会发出 'catch',您可以在 catch 块中处理它。

try{
let res1 = await your-async-function(parameters);
let res2 = await your-promise-function(parameters);
await your-async-or-promise-function(parameters);
}
catch(ex){
// your error handler goes here
// error is caused by any of your called functions which fails its promise
// this methods breaks your call chain
}

你也可以像这样处理你的'catch':

let result = await your-asyncFunction(parameters).catch((error)=>{//your error handler goes here});

提到的这个方法不会产生异常,所以继续执行。

我认为async/await 除了原生 Promise 模块实现之外没有任何性能差异。

我建议使用bluebird 模块而不是node 内置的原生promise。

【讨论】:

    【解决方案3】:

    此时使用 Promises 的唯一原因是使用 Promise.all() 调用多个异步作业,否则通常使用 async/await 或 Observables 会更好。

    【讨论】:

    • 您可以使用Promise.all()async/awaitconst [p1, p2, p3] = await Promise.all([p1(), p2(), p3()]);
    • p1,p2,p3 都是该实例中的经典承诺。如果您单独等待它们中的每一个,它们将被同步执行。
    • 它们都同时执行。在调用下一个之前,我们不会等待一个完成。我们只是等待所有人完成Promise.all()
    • 没错。但是如果你调用 await p1()、await p2、await p3,它们将是并发的。 p1-p3 必须声明为明确的承诺。
    • 如果这个答案能解释 why如何 使用 async/await 或 Observables 会更好。正如所写的那样,对于尚未熟悉这些主题的人来说,这似乎不是很有帮助。
    【解决方案4】:

    这取决于你擅长什么方法,promise 和 async/await 都很好,但是如果你想写异步代码,使用同步代码结构你应该使用 async/await 方法。就像下面的例子,一个函数返回具有 Promise 或 async/await 风格的用户。 如果我们使用 Promise:

    function getFirstUser() {
        return getUsers().then(function(users) {
            return users[0].name;
        }).catch(function(err) {
            return {
              name: 'default user'
            };
        });
    }
    

    如果我们使用 aysnc/await

    async function getFirstUser() {
        try {
            let users = await getUsers();
            return users[0].name;
        } catch (err) {
            return {
                name: 'default user'
            };
        }
    }
    

    在 promise 方法中,我们需要一个 thenable 结构来遵循,而在 async/await 方法中,我们使用 'await' 来保持异步函数的执行。

    您可以查看此链接以获得更清晰的信息访问https://medium.com/@bluepnume/learn-about-promises-before-you-start-using-async-await-eb148164a9c8

    【讨论】:

      【解决方案5】:

      昨天我做了一个初步决定,从使用 Promises 切换到使用 Async/Await,独立于 nodejs,基于访问 Promise 链中先前值的困难。我确实提出了一个紧凑的解决方案,使用 'bind' 将值保存在 'then' 函数中,但 Async 在允许直接访问局部变量和参数方面似乎更好(而且确实如此)。当然,Async/Await 更明显的优势是消除了令人分心的显式“then”函数,取而代之的是看起来很像普通函数调用的线性表示法。

      但是,我今天的阅读发现了 Async/Await 的问题,这使我的决定偏离了方向。我想我会坚持使用 Promises(可能使用宏预处理器使“then”函数看起来更简单),直到 Async/Await 得到修复,几年后。

      这是我发现的问题。我很想知道我错了,这些都有简单的解决方案。

      1. 需要外部的 try/catch 或最终的 Promise.catch(),否则会丢失错误和异常。

      2. 最终的等待需要 Promise.then() 或额外的外部异步函数。

      3. 只能使用 for/of 正确完成迭代,不能使用其他迭代器。

      4. Await 一次只能等待一个 Promise,而不是像 Promise 链中的 Promise.all 这样的并行 Promise。

      5. Await 不支持 Promise.race(),如果需要的话。

      【讨论】:

      • 1 对于 Promises 和 Async Await 都为真
      • 你能详细说明3吗?
      • 我将 #3 建立在我读到的一些我再也找不到的东西上。事实上,jakearchibald.com/2017/async-iterators-and-generators,从大约 3 年前的 Chrome 开始,表明异步与迭代器一起工作得很好。不知道这篇文章对Chrome等浏览器是否还有效,也没有时间尝试这种异步技术。
      猜你喜欢
      • 1970-01-01
      • 2017-06-15
      • 1970-01-01
      • 2018-10-17
      • 2018-03-02
      • 1970-01-01
      • 2019-12-03
      • 2018-02-03
      相关资源
      最近更新 更多