这是我参与「第四届青训营 」笔记创作活动的第10天。异步编程一直是写js时常见的问题。本文介绍了三种异步编程解决方案,包括Promise、async和generator
Promise
Promise的三种状态
- 待定 pending
- 成功 fulfilled
- 失败 rejected
Promise中只有两种状态改变模式:
- pending --> fulfilled;
- pending --> rejected
Promise的方法
- promise.then(): 返回一个Promise对象,状态根据内部执行结果决定
- promise.catch:用于捕获异常的方法,差不多是.then()方法写错误回调函数的语法糖。
- promise.finally:最后不管promise的状态如何,都会执行的代码。
- promise.all: Promise.all([promise1,promise2,promise3,promise4]).then()。所有promise都变为fulfilled才触发then()的resolve。如果有一个状态变成了rejected,那么all方法的状态就会变成rejected。
- promise.race
- promise.resolve:返回一个状态为fulfilled的Promise对象,值为参数中回调函数return的值。
- promise.reject:返回一个状态为rejected的Promise对象,值为参数中回调函数return的值。
练习题
function fn() {
return new Promise((resolve) => {
console.log("Promise1")
fn1()
setTimeout(() => {
console.log('Promise2')
resolve()
console.log('Promise3')
}, 0)
})
}
async function fn1() {
var p = Promise.resolve().then(() => {
console.log('Promise6')
})
await p.then(() => {
console.log('Promise7')
})
console.log('end')
}
console.log('script');
setTimeout(() => {
console.log('setTimeout')
}, 0)
fn().then(() => {
console.log('Promise4')
})
// script promise1 Promise6 Promise7 end setTimeout promise2 promise3 promise4
async
是promise和generator函数的语法糖。promise函数虽然解决了回调地狱的问题,但是语意不够清晰,generator函数需要手动调用next(),使得代码向下运行,不够便利。
async函数调用时会直接执行到内部第一个await后面的语句,之后的语句需要阻塞到await后面的语句执行完成。
特性
- async函数内部会返回一个promise对象
- await能获取到promise状态改变后的
值
,若后面不是promise对象,则将它隐式转为已经正常处理的promise对象的resolve值。 - 若await后promise的状态是reject,则await后的代码不会执行,async返回状态为reject的promise
- 若async函数内部有await,则await下面的代码被阻塞,await后的promise对象状态为fulfilled时才往下执行。
async function fn(){
setTimeout(()=>{
console.log(1)
},0)
Promise.resolve().then(()=>{console.log(4)});
await setTimeout(function(){
console.log(5)
},0);
//等价于
// await Promise.resolve(setTimeout(function(){
// console.log(5);
// }),0).then(()=>undefined);
await Promise.resolve().then(()=>{
console.log(6)
})
Promise.resolve().then(()=>{
console.log(7)
})
console.log(3);
}
fn();
// 4 6 3 7 1 5
generator
Generator 生成器函数,返回 遍历器对象。返回到遍历器对象中,使用对象的.next()方法控制函数内部的代码向下执行,执行到下一个 yield 关键字之前的代码,或者函数结尾处。并且next()方法会返回一个对象,对象内部有value,done两个属性{value:yield后的值/undefined,done:true/false};done为false时,表示已经走到了函数末尾。