前端应用中时常出现多个异步方法需要依次调用,且后一个异步方法的执行依赖于前一个异步方法的返回结果的情况,下面主要介绍一下这种情况的处理方法。
方法1:异步方法嵌套调用
此种方法逻辑简单,但代码较为繁琐。
方法2:使用async函数
(参考ES6 async函数)
ES2017 标准引入了 async 函数,使得异步操作变得更加方便。
2.1 用法
在函数的前面加上async
关键字,表明该函数内部有异步操作。该函数在执行的时候遇到await
就会返回,再接着执行函数体后面的语句。
正常情况下,await
命令后面是一个Promise 对象
,返回该对象的结果;如果不是Promise对象,就直接返回对应的值。
async function getStockPriceByName(name) {
const symbol = await getStockSymbol(name);
const stockPrice = await getStockPrice(symbol);
return stockPrice;
}
getStockPriceByName('goog').then(function (result) {
console.log(result);
});
async函数
返回一个 Promise 对象
,可以使用then方法
添加回调函数。函数内部的return
语句的返回值,会成为then方法
回调函数的参数。
如果async函数
内部抛出错误,则会导致返回的 Promise 对象变为reject
状态。抛出的错误对象会被catch方法回调函数接收到。
注意: 任何一个
await
语句后面的 Promise 对象变为reject
状态,那么整个async函数都会中断执行。
async function f() {
await Promise.reject('出错了');
}
f()
.then(v => console.log(v))
.catch(e => console.log(e))
// 出错了
async function f() {
await Promise.reject('出错了');
await Promise.resolve('hello world'); // 不会执行
}
2.2 错误处理
如果希望即使前一个异步操作失败,也不要中断后面的异步操作,可以使用下面两种方法:
- 可以将第一个await语句放在
try...catch
结构里面,这样不管这个异步操作是否成功,第二个await都会执行。如果有多个await命令,可以统一放在try...catch
结构中。
async function f() {
try {
await Promise.reject('出错了');
} catch(e) {
}
return await Promise.resolve('hello world');
}
f().then(v => console.log(v))
// hello world
- await后面的 Promise 对象再跟一个catch方法,处理前面可能出现的错误。
async function f() {
await Promise.reject('出错了')
.catch(e => console.log(e));
return await Promise.resolve('hello world');
}
f()
.then(v => console.log(v))
// 出错了
// hello world
2.3 Promise 对象的状态变化
async函数
返回的 Promise 对象,必须等到内部所有await
命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。也就是说,只有async函数内部的异步操作执行完,才会执行then方法
指定的回调函数。
注意: await命令只能用在async函数之中,如果用在普通函数,就会报错。
方法3:使用Rxjs操作符
3.1 使用zip
操作符(参考RxJS-zip)
使用zip
方法将多个 Observable 组合以创建一个 Observable,该 Observable 的值是由所有输入 Observables 的值按顺序计算而来的。
如果最后一个参数是函数,这个函数被用来计算最终发出的值;否则,返回一个顺序包含所有输入值的数组。
使用时需要在文件中导入操作符:
import { zip } from 'rxjs';
zip(
observable1,
observable2,
).subscribe(([result1, result2]) => {
// do something
});
— END —