在很长一段时间里面,前端工程师不得不依靠回调来处理异步代码。使用回调的结果是,代码变得很纠结,不便于理解与维护,值得庆幸的是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的使用async函数完全可以看作多个异步 *** 作包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。
// 函数声明
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回调。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)