【问题标题】:Async/await vs Promise异步/等待与承诺
【发布时间】:2019-07-29 20:53:12
【问题描述】:

对最佳实践感到困惑。

Using async-await is better than using promises.是吗?

如何判断aync/awaitpromises的用途?

下面我只是写了两个代码sn-ps。一个使用aync/await,另一个不使用。

哪个会更快?

CASE 1 的优势是什么?

哪个是最新的方法和优势?

案例一

var promise1 = rp('https://api.example.com/endpoint1');
var promise2 = rp('https://api.example.com/endpoint2');

var response1 = await promise1;
var response2 = await promise2;
return response1 + ' ' + response2;

案例 2

var promise1 = rp('https://api.example.com/endpoint1');
var promise2 = rp('https://api.example.com/endpoint2');

return Promise.all([promise1, promise2])
.then(function(values){
    return values[0] + values[1];
});

【问题讨论】:

  • async/awaitfor Promises 不是 Promises
  • 能否请您回顾一下这两个案例,它们之间有什么区别?
  • Async/await 只是编写 Promise 的花哨语法。所以大多数会归结为偏好。案例 1 写起来更短。案例 2 让我们更难忘记函数是异步的。我是那些发现承诺链更容易遵循的人之一。
  • @slideshowp2 — 不。promise 都在 eitherawaited 之前初始化。它们将在两种情况下并行执行。
  • 您的情况几乎相同。但是如果你这样做 var r1 = await rp('https://api.example.com/endpoint1'); var r2 = await rp('https://api.example.com/endpoint2') 行为会有所不同:请求将按顺序运行。

标签: javascript node.js asynchronous promise async-await


【解决方案1】:

使用 async-await 比使用 Promise 更好

没有。 asyncawait 是帮助您管理承诺的工具。

哪个会更快?

不太可能有任何明显的差异

CASE 1 的优势是什么?

有些人会认为它更简单、更容易理解。其他人可能不同意。

【讨论】:

  • 在 CASE 2 中,并行执行 Promise。在 CASE 1 一个接一个。
  • response2只有在得到response1后才会得到。是写的吗?
  • @AshwanthMadhav — 不。它们在两种情况下并行执行。异步过程在调用rp() 时开始。该函数返回一个承诺。当到达await 语句时,调用函数进入睡眠状态。那是 两个调用rp之后。即在第二次调用 rp() 之前它不会进入睡眠状态,因此第二个异步进程开始时没有延迟。
  • 目前我正在使用与@kuba 所说的相同的概念。我无法理解这两个 await 同时工作。当我们在每条等待线之后进行安慰时,在去var response2 = await promise2;这一行之前,我可以打印respons12的结果
【解决方案2】:

Async/await 在底层被翻译成 Promise。

因此,两者的性能是相同的。

您应该始终使用 async/await,除非有一些技术限制,因为它更容易理解。

现在,正如其他人提到的,目前两个代码示例并不相等。 但是由于您使用的是await,这意味着您的rp() 返回了一个承诺。因此,您可以将第一个案例重写为:

let [r1, r2] = await Promise.all([promise1, promise2])
return r1 + r2

为了达到同样的效果。

【讨论】:

  • 在 CASE 2 中,并行执行 Promise。在CASE 1中一个接一个。 response2 只有在得到 response1 后才会得到。是写的吗?
  • 您可以以相同的方式重写使用 async/await 的函数。我更新了我的答案来证明它。
  • 我得到了你的答案。但是请您解释一下案例 1 和案例 2 的区别。他们中的大多数人都说,ith 具有相同的性能。
  • 您的代码似乎不错。当对 promise1 和 promise2 使用 await 时,会花费一些时间。对吗?
【解决方案3】:

使用 async-await 比使用 Promise 更好。

哪个会更快?

最新的方法和优势是什么?

无论是语法还是您的任何一种方法都没有提供任何优于另一种的特殊优势,但此外,您的方法并不能很好地显示您的意图。您不需要为了同时获得它们的结果而保留对 Promise 的显式引用:

const [response1, response2] = await Promise.all([
  rp('https://api.example.com/endpoint1'),
  rp('https://api.example.com/endpoint2')
]);
...

请记住,上述方法必须包含在 async 函数中。它不能像这种方法那样存在于顶级范围内:

Promise.all([
  rp('https://api.example.com/endpoint1'),
  rp('https://api.example.com/endpoint2')
]).then(([response1, response2]) => {
  ...
});

【讨论】:

  • 但是对于使用 await 时,下一行仅在得到结果后执行。有两个等待。所以等待双方的回应。 Promise.All 并行执行。那么异步如何变得更好呢?只是为了理解吗?
  • @AshwanthMadhav There is two awaits。我不太确定你的意思。只有一个awaitThen how async become better? 没有。这是风格偏好的问题。使用任何一种方法使您的代码更具可读性和更易于理解,几乎没有性能差异,当然除了样式之外,您应该关心这两个示例之间的差异。
  • 当在response1下安慰时,会有那个promise的结果。同理,在response2下安慰时,有结果。但是有时间解决这两个承诺
  • @AshwanthMadhav 您的评论仍然没有意义。你说的是我提供的例子还是没有?
【解决方案4】:

Await 用于评估已解决或已拒绝的 Promise。所以使用 .then 和 await 的功能是一样的。但是 await 使代码更具可读性,因为您不会进入一系列回调。使用 await,您可以将异步函数视为使用 await 的同步函数。

让我们举个例子。我们有一个 API 和 2 个数据库,我们想从其中一个数据库中取一个名称并插入到另一个数据库中。为此,我们必须从数据库 1 中获取数据。等待它到达我们的客户端,然后通过 POST 请求将其发送到我们的 API 以插入。 [您可以使用 ONE 功能服务器端完成所有这些操作,但对于我们的案例,我们将发出 2 个异步获取请求来回答这个问题]。如果我们想在函数中使用 .then 来解决这个问题,它看起来像这样。

function get_and_set(){
   fetch("https://www.some_api.com/get_random_name")
   .then( response => response.text() )
     .then( name => {
       fetch("https://www.some_api_2.com/insert_name", {
        headers : {
          "Body-Type"    : "application/json",
          "Accept"       : "application/json"
        },
        method : "POST",
        body : JSON.stringify({ name : name })
      })
      .then( set_response => set_response.text() )
        .then( set_response => {
           return set_response;
        })
     )}

}

如果我们选择使用带有 await 的异步函数,我们可以改为这样。在我个人看来,这变得更具可读性。

async function get_and_set(){
  let response = await fetch("https://www.some_api.com/get_random_name")
  let name = response.text();

  let insert_response = await fetch("https://www.some_api_2.com/insert_name", {
     headers : {
        "Body-Type"    : "application/json",
        "Accept"       : "application/json"
     },
     method : "POST",
     body : JSON.stringify({ name : name })
  });
  let success = insert_response.text();

  return (success); //Return the status of how the insertion went
}

【讨论】:

  • 当我们在第二个API中使用第一个响应时使用它。
【解决方案5】:

所有当前的回答当然都是正确的,但请记住一些差异。

目前,在您的两个解决方案中,promise 都是并行调用的。这可能会导致一些错误。

考虑这种情况(对您的情况 1 稍作修改):

var response1 = await rp('https://api.example.com/endpoint1');
var response2 = await rp('https://api.example.com/endpoint2');

return response1 + ' ' + response2;

在上述情况下,promise2 将在 promise1 完成自身执行后执行。当promise2 启动时,结果就已经知道了。另一方面,您的案例在某种竞赛中一起运行。因此,如果在对rp 的第二次调用中包含依赖于在第一次调用rp 时执行的某些操作的逻辑,则可能会导致意外结果甚至崩溃。很好的例子是写入和读取同一个文件。

让我们考虑以下示例:

function writeToFile()
{
   return new Promise((resolve, reject) => {
      ... // writing to file abc.txt
   };
}

function readFile()
{
   return new Promise((resolve, reject) => {
      ... // reading file abc.txt
   };
}

function raceCondition() 
{
   Promise.all([
       writeToFile(),
       readFile()
   ]);
} 

async function asyncAwait() 
{
   await writeToFile();
   await readFile();
} 

raceCondition() 函数可能会导致意外行为,因为 readFile 可能会在 writeToFile 函数甚至没有完成写入文件时运行。它可能导致读取一些旧数据,甚至文件可能不存在。

asyncAwait() 函数使用 async/await 方法来保证writeToFile() 函数在读取开始之前完成其工作。当然这并不意味着程序变得同步。同时执行其他操作(即一些 GUI 事件处理等)。

Async/Await 应被视为 .then().then() 链的替代方案,而不是 Promise.all

【讨论】:

  • 这里readFile是在writeToFile之后才执行的。在我的情况下,没有必要一个接一个。两者都将并行执行对我来说可能更好。这两个功能是独立的。
  • 是的,你是对的,只是想指出使用Promise.all可能存在的陷阱
猜你喜欢
  • 2017-06-15
  • 1970-01-01
  • 2018-10-17
  • 2018-03-02
  • 1970-01-01
  • 2018-02-03
  • 2018-03-05
  • 1970-01-01
  • 2020-03-26
相关资源
最近更新 更多