一、Promise篇
1.1 Promise基本用法
// getCaseId 函数new Promise构造函数,生成了一个Promise实例。
// new Promise() 是创建Promise实例的方法。
function getCaseId() {
return new Promise((resolve, reject) => {
const success = true
setTimeout(function () {
if (success) {
resolve('成功') // pending -> resolved 一旦改变,状态就凝固了,不会再变了。
}
reject('失败') // pending -> rejected
},3000)
})
}
// Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数
getCaseId()
.then(res => {
console.log(res) // res是resolve() 里的值
}) // then () 返回的还是个Promise实例
.catch(err => { // err 是rejected() 里的值
console.log(err)
})
- Promise对象是一个构造函数,用来生成Promise实例。
- Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。
resolve: pending->resolved 状态。
rejected: pending->rejected 状态。
- Promise.prototype.then() : 执行完resolve(),状态变为resolved状态时去调用。then()返回的还是个Promise的实例。
- Promise.prototype.catch() :执行完rejected(),状态变为rejected状态时去调用,捕获错误。
Promise链式调用
return checkAllowApplyClaim().then(getOrderBrief).then(getMaterialGroupList);
getOrderBrief是作为回调函数进去的,和Promise.then(res => {})中的res=> {} 是一样的,会自己执行这个回调。
1.2 Promise静态方法
1.3 Promise.all()
Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。成了一个Promise实例。
const p = Promise.all([p1, p2, p3]);
p的状态由p1、p2、p3决定,分成两种情况。
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值(resolve()返回的值)组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
适合 希望一个失败就失败的场景
promise.all [
let a = new Promise(); // a 和 b都是Promise的实例
let b = new Promise();
]
注意:2个请求同时发出,a和b 不能确定返回顺序。 即a是否返回对b没有影响。
1.4 Promise.race()
Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.race([p1, p2, p3]);
只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
Promise.allSettled()
只有等到所有这些参数实例都返回结果,不管是fulfilled还是rejected,包装实例才会结束.该方法由 ES2020 引入。
二、async篇
ES2017 标准引入了 async 函数,使得异步操作变得更加方便。
2.1 定义
async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
- 同步方式写异步
- 解决Promise回调地狱(有依赖关系那种)的问题。
async function main() {
try {
const val1 = await firstStep(); // await后面一个promise对象,val1的值是firstStep里reslove()的值
const val2 = await secondStep(val1);
const val3 = await thirdStep(val1, val2);
return [...val1, ...val2, ...val3]
}
catch (err) { // err 是rejected的值
console.error(err);
}
}
main().then(res => {
console.log('111')
}).catch(err => {
console.log(err)
}) // catch 不会走了,已经捕获了。所以没必要写。
改为:main();
async函数返回的 Promise 对象,必须等到内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。
也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。
async函数内部return语句返回的值,会成为then方法回调函数的参数.
2.2 await
- 正常情况下,await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。
- await命令后面的 Promise 对象如果变为reject状态,则reject的参数会被catch方法的回调函数接收到
- await 之间有继发关系,val1 走了才有val2 ,即同步方式写异步。缺点时:比较耗时。
所以,没有依赖关系的,完全可以让它们同时触发。
let [val1, val2] = await Promise.all([firstStep(), secondStep()]);
2.3 try {} catch(e) {}
请求失败后的处理, 可以使用try-catch来进行
- await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try...catch代码块中。
firstStep(),返回rejected状态时,就走catch了捕获了错误,后面的secondStep thirdStep 都不会执行。
- await 之间有继发关系,val1 走了才有val2 ,即同步方式写异步。
缺点时:比较耗时。所以,没有依赖关系的,完全可以让它们同时触发。多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。
let foo = await getFoo();
let bar = await getBar();
上面代码中,getFoo和getBar是两个独立的异步操作(即互不依赖),被写成继发关系。这样比较耗时,因为只有getFoo完成以后,才会执行getBar,完全可以让它们同时触发。
let [foo, bar] = await Promise.all([getFoo(), getBar()]);