async await

async await,第1张

背景

在很长一段时间里面,前端工程师不得不依靠回调来处理异步代码。使用回调的结果是,代码变得很纠结,不便于理解与维护,值得庆幸的是Promise带来了.then(),让代码变得井然有序,便于管理。于是我们大量使用,代替了原来的回调方式。但是不存在一种方法可以让当前的执行流程阻塞直到promise完成。JS里面,我们无法直接原地等promise完成,唯一可以用于提前计划promise完成后的执行逻辑的方式就是通过then附加回调函数。 现在随着ES7中async await的增加,可以让接口按顺序异步获取数据,用更语义化,可维护的方式处理回调。

介绍

async await是一个期待已久的JavaScript特性,让我们更好的理解使用异步函数。它建立在Promises上,并且与所有现有的基于Promise的API兼容。

async

语法:async function foo(){…}

作用:声明一个异步函数

自动将常规函数转换成Promise,返回值也是一个Promise对象只有async函数内部的异步 *** 作执行完,才会执行then方法指定的回调函数异步函数内部可以使用await await

语法:var result = await someAsyncCall()

作用:暂停异步的功能执行

放置在Promise调用之前,await强制其他代码等待,直到Promise完成并返回结果只能与Promise一起使用,不适用与回调只能在async函数内部使用

async函数完全可以看作多个异步 *** 作包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。

使用 async的使用
// 函数声明
async function foo() {}

// 函数表达式
let foo = async function() {}

// 对象的方法
const obj = {
  async foo() {}
}
console.log(obj.foo()) // Promise对象,值为undefined
obj.foo().then(() => console.log(1)) // 1

// 箭头函数
let foo = async () => {}
await的使用

await的用法则相对简单了很多,它后面需要是一个Promise对象,如果不是则会被转成Promise对象。只要其中一个Promise对象变为rejected状态,那么整个async函数都会中断 *** 作。如果状态是fulfilled,那么它的返回值则会变成then里面的参数,如下:

// await
async function foo() {
  return await 123
}
foo().then(res => { console.log(res) }) // 123

// class的方法
class Storage {
  constructor() {
    this.cachePromise = caches.open('avatars')
  }
  async getAvatar(name) {
    const cache = await this.cachePromise
    return cache.match(`/avatars/${name}.jpg`)
  }
}
const storage = new Storage()
storage.getAvatar(1).then((res) => {console.log(res)}) // undefined
由于await后面的promise运行结果可能是rejected,最好把await放入try/catch中await后的异步 *** 作,如果彼此没有依赖关系最好同时触发await只能在async函数之中,如果在普通函数中,会报错 使用场景

1、同时发出多个不互相依赖的请求,不适合使用async await

async function getDatas() {
  let A = await getValueA()
  let B = await getValueB()
  let C = await getValueC()
  return A + B + C
}

上面我们A需要2s,B需要4s,C需要3s,我们如果这样发请求,就存在彼此依赖的关系,c等b执行完,b等a执行完,从开始到结束需要(2+3+4)9s。

此时我们需要用Promise.all()将异步调用并行执行,而不是一个接一个执行,如下所示:

async function getDatas() {
  let results = await Promise.all([getValueA, getValueB, getValueC])
  return results.reduce((total, item) => total + item)
}

这样将会节省我们不少的时间,从原来的的9s缩减到4s。

2、发出多个互相依赖的请求,适合使用async await

一个提交表单的页面,里面有姓名、性别等信息,其中有一项是手机验证码,我们不得不等待手机验证码接口通过,才能发出后续的请求 *** 作,这时候接口之间就存在了彼此依赖的关系,async await就有了用武之地,让异步请求之间可以按顺序执行。

其中不用async await的写法,我们不得不用.then()的方式,在第一个请求验证码的接口有返回值之后,才能执行后续的Promise,并且还需要一个then输出结果,如下:

// 获取手机验证码的请求
let callPromise1 = fetch('http://api/getCode')
callPromise1.then(res => res.json())
            .then(json => {
              // 对验证码的返回值进行后续的 *** 作,如提交表单等
              let callPromise2 = fetch('http://api/postForm')
              return callPromise2
            })
            .then(res => res.json())
            .then(json => {
              // 输出执行完以后的结果
              console.log(json.resCode)
            })
            .catch(err => console.log(err))

而用async await的方式去写就是下面这样,我们将逻辑分装在一个async函数里。这样我们就可以直接对Promise对象使用await了,也就规避了写then回调。最后我们调用这个async函数,然后按照普通的方式使用返回的promise:

// 提交表单的请求
async function postForm() {
  try {
    // 手机验证码是否通过,拿到返回的json
    let res1 = await fetch('http://api/getCode')
    let json1 = await res1.json()
    let json2
    // 对第一个接口的返回数据进行判断,满足条件就请求第二个接口,并返回数据
    if (json1.resCode === 200) {
      const res2 = await fetch('http://api/postForm')
      json2 = await res2.json()
    }
    return json2
  } catch (err) {
    console.log(err)
  }
}
// 执行postForm
postForm().then(json => console.log(json))
总结

async await让我们用少量的代码来使用Promise,我们可以将一些有依赖关系的回调函数的处理逻辑放在async里面,然后在非async的区域使用,这样可以减少then或者catch回调。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1320166.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-11
下一篇 2022-06-11

发表评论

登录后才能评论

评论列表(0条)

保存