代码之家  ›  专栏  ›  技术社区  ›  VSO

为什么Async总是返回一个承诺?

  •  0
  • VSO  · 技术社区  · 7 年前

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

    这么说,为什么 async 关键字是否在Promise中包装异步函数的返回值?有什么意义?只是因为 await 表达需要承诺?或者这个决定背后有什么意义/用途?

    2 回复  |  直到 7 年前
        1
  •  3
  •   Happy Machine    7 年前

    我想我之所以回答这个问题,主要是因为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仅在scopedvariable完成时设置它,因此当我们记录它时,该变量是未定义的。

    但是如果

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

    当我们等待promise并且setTimeout完成时,resolve函数设置变量,以便当我们控制台记录它时,它保存来自promise的值。

    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()
    

    你可以用“等待”和“交换”。

    例如,我们可以去:

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

    代码将再次在处暂停。然后在AsyncEvent承诺解决后继续。

    实际上,如果我们使用。那么我们不需要将它包含在异步函数中,这样我们就可以像这样重写它。

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

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

    为了使用await,您需要在一个异步函数(因此上面的异步容器函数)内。这不是必需的。那么,但是。那么和。锁链会使代码混乱。

    希望这有帮助!

        2
  •  1
  •   Barmar    7 年前

    这个 async await 运算符只是语法上的糖分,它隐藏了实现异步代码的承诺的底层用法。

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

    使用 等待 在异步函数调用挂起当前函数之前,直到它返回的承诺得到解决。它基本上相当于将函数的其余部分包装在一个匿名函数中,并将其用作 .then() 收回承诺。

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