为什么异步总是返回承诺?

时间:2019-01-01 00:03:48

标签: javascript async-await

这个问题是理论上的-我没有要解决的具体问题。

这么说,为什么async关键字将一个异步函数的返回值包装在promise中呢?重点是什么?仅仅是因为await表达式期望一个诺言吗?还是这个决定背后有一些意义/用途?

2 个答案:

答案 0 :(得分:3)

我想我之所以会回答这个问题,主要是因为Javascript中的异步曾经使我烦恼,突然间它突然崩溃了,所以我希望这个比喻可以帮助您实现这一目标。

您有一个异步事件。这可以是任何事情,可以从服务器上获取某些东西,在浏览器中完成需要花费时间的事情,训练机器学习模型(!),执行使用setTimeout的函数或方法等。

Javascript的美丽以及它在浏览器中运行良好的一个关键原因是,它以一种非常聪明的方式使用了运行于其上的处理器线程,从而阻止了该线程被耗时的进程阻塞(例如所提到的进程)以上)

许多其他语言(例如Ruby)在多个线程上运行。可以使用服务程序在javascript中的多个线程上运行进程,但这不在此答案的范围内!

JS事件循环的异步特性允许线程在等待进程完成时“离开”并执行其他操作。

从编程的角度来看,这样做的问题是,如果不等待,依赖于阻塞事件的结果的代码中的某些内容可能会由于事件的结果而变得“未定义”事件在尝试使用其结果之前完成。在下面使用这段代码

let scopedVariable
console.log('the code has started')
setTimeout(() => {
  scopedVariable="I am the result of some async process"
}, 5000);
console.log(scopedVariable)

当代码到达控制台日志时,setTimeout尚未完成。由于setTimeout仅在完成时才设置scopedVariable,因此在我们记录该变量时未定义该变量

但是

我们将超时包装在一个Promise中,我们可以等待它的resolve回调(Promise的第一个参数),并且代码将“暂停”直到Promise到达resolve回调,然后继续。

当我们等待诺言并且setTimeout完成时,resolve函数会设置变量,以便在我们控制台日志中它保存诺言中的值

let scopedVariable
const asyncEvent = new Promise ((resolve,fail) => {
  setTimeout(() => {
    resolve(scopedVariable="I have resolved")
  }, 5000);
})
const container = async () => {
  const result = await asyncEvent
  console.log(scopedVariable)
}

container()

您可以使用await和.then进行互换

例如,我们可以去

let scopedVariable
const asyncEvent = new Promise ((resolve,fail) => {
  setTimeout(() => {
    resolve(scopedVariable="I have resolved")
  }, 5000);
})
const container = async () => {
  asyncEvent.then(() => console.log(scopedVariable))
}

container()

再次,代码将在.n处暂停,然后在asyncEvent承诺解决后继续。

实际上,如果我们使用.then,则无需将其包含在异步函数中,因此我们可以像这样重写它

let scopedVariable
const asyncEvent = new Promise ((resolve,fail) => {
  setTimeout(() => {
    resolve(scopedVariable="I have resolved")
  }, 5000);
})

asyncEvent.then(() => console.log(scopedVariable))

.then的优点是,随附的.catch允许您捕获异步事件引发的任何错误(例如,如果在发生错误时从服务器检索某些内容)。对于异步等待,您需要将潜在危险的函数包装在try catch中。

要使用await,您需要位于一个异步函数内部(因此,上面的异步容器函数)。 .then不需要这样做,但是.then和.catch链会使您的代码混乱。

我希望这会有所帮助!

答案 1 :(得分:1)

asyncawait运算符只是语法糖,它们隐藏了实现异步代码的promise的基本用法。

在函数定义之前使用async会使函数返回一个承诺,该承诺会解析为函数的返回值,而不是正常返回。

在异步函数调用之前使用await会挂起当前函数,直到解决了返回的诺言为止。从根本上讲,这等效于将函数的其余部分包装在一个匿名函数中,并将其用作promise的.then()回调。

有关这种关系的更多信息,请参见How to translate Promise code to async await