Promise是异步问题同步话的一个解决最优方案、在前很多年的时候一般异步处理的方式大多都是callBack形式、因为callBack的形式也会导致无法通过return的形式把结果返回出去、还有一个就是callBack过多会导致地狱嵌套严重的问题、promise还封装了多个异步同时执行的能力、通过Promise我们能够写出更优雅的异步解决方案!
Promise状态
- pending (初始化-等待执行)
- fulfilled (执行成功)
- rejected (操作失败)
每种状态执行完都会触发对应的 链式方法、promise只允许一种状态要么成功要么失败
/* 成功案例 */let p = new Promise( (resolve) =>{setTimeout(() => { resolve(1) }, 100);})console.log(p) // Promise {<pending>}// 通过then接收执行成功的结果p.then( res =>{console.log(res); // 1秒后得到 1console.log(p) // Promise {<fulfilled>: 1}return new Promise( resolve =>{setTimeout( () => resolve({'name':'张三'}) , 2000)})}).then( res =>{console.log(res); // {name: '张三'}return {age:100}}).then( res =>{console.log(res) // {age: 100}}).finally( () =>{ //不管成功或失败都会执行console.log('当前promise运行完成')})/* 失败案例 */let p2 = new Promise( (resolve, reject) =>{setTimeout(() => { reject('失败了') }, 1000);})console.log('p2',p2) // Promise {<pending>}p2.catch( err =>{console.log('err',err) // 失败了console.log('p2 status',p2) // p2 status Promise {<rejected>: '失败了'}nsole.log('err',err) // Uncaught (in promise) 失败了})
then也返回一个promise对象、是promise就 会存在then方法、在then方法里面直接return 或者返回一个promise状态都能够在继续使用.then方法进行接收、有点像俄罗斯套娃了、嵌套在一起!
promise.all()
接收一个Promise可迭代(iterable)类型(注:Array,Map,Set都属于ES6的iterable类型)、只要任何一个输入的promise的reject回调执行或者输入不合法的promise就会立即抛出错误、那这个Promise.all也会被标记reject状态
let p1 = new Promise( resolve =>{setTimeout( () => resolve(1),1000)})let p2 = new Promise( resolve =>{setTimeout( () => resolve(2),1500)})let p3 = new Promise( resolve =>{setTimeout( () => resolve(3),2000)})Promise.all([ p1, p2, p3 ]).then( res =>{console.log(res) // [1, 2, 3]}).catch( err =>{console.log(err)})// 某个状态为rejectlet p4 = new Promise( resolve =>{setTimeout( () => resolve(1),1000)})let p5 = new Promise( (resolve,reject) =>{setTimeout( () => reject('失败了'),1500)})Promise.all([ p4, p5 ]).then( res =>{console.log(res)}).catch( err =>{console.log(err) // 失败了})
Promise.allSettled()
接收一个Promise可迭代(iterable)类型(注:Array,Map,Set都属于ES6的iterable类型)、返回每一个promise的状态和结果, 弥补了promise.all遇到reject就直接返回reject的问题、Promise.allSettled() 优于Promise.all
let p4 = new Promise( resolve =>{setTimeout( () => resolve(1),1000)})let p5 = new Promise( (resolve,reject) =>{setTimeout( () => reject('失败了'),1500)})Promise.allSettled([ p4, p5 ]).then( res =>{/* 得到{status: 'fulfilled', value: 1}{status: 'rejected', reason: '失败了'}*/console.log(res)}).catch( err =>{console.log(err)})
Promise.any()
接收一个Promise可迭代(iterable)类型(注:Array,Map,Set都属于ES6的iterable类型),只要其中的一个 promise 成功,就返回那个已经成功的 promise 。如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝)就返回reject状态
let p4 = new Promise( (resolve,reject) =>{setTimeout( () => resolve(1),2000)})let p5 = new Promise( (resolve,reject) =>{setTimeout( () => reject('失败了'),1500)})let p6 = new Promise( (resolve,reject) =>{setTimeout( () => resolve(2222),2500)})Promise.any([ p4, p5, p6 ]).then( res =>{console.log(res) // 1}).catch( err =>{console.log('err',err)})
Promise.race()
接收一个Promise可迭代(iterable)类型(注:Array,Map,Set都属于ES6的iterable类型),一旦迭代器的某个promise状态被返回(不管是reject还是resolve)都返回出去
let p4 = new Promise( (resolve,reject) =>{setTimeout( () => resolve(1),2000)})let p5 = new Promise( (resolve,reject) =>{setTimeout( () => reject('失败了'),1500)})let p6 = new Promise( (resolve,reject) =>{setTimeout( () => resolve(2222),2500)})Promise.race([ p4, p5, p6 ]).then( res =>{console.log(res)}).catch( err =>{console.log('err',err) // err 失败了})
Promise.resolve
把一个结果包装成一个成功的promise、即可使用then接收、场景可用来组装参数同步化一次性返回出去
let use = {name:'zhangsan'}let p1 = new Promise( resolve => resolve(2))let p = Promise.all([ Promise.resolve(use), p1]);p.then( res =>{console.log(res)})
Promise.reject()
把一个结果包装成一个失败的promise、即可使用catch接收
let use = {name:'zhangsan'}let p1 = new Promise( resolve => resolve(2))let p = Promise.race([ Promise.reject(use), p1]);p.then( res =>{console.log(res)}).catch(err =>{console.log(err) // {name: 'zhangsan'}})
异步问题同步化方案
上面案例都是基于异步的then方式接收结果、那有没有可以和同步代码并行执行呢、答案是:可以的
async await
let p1 = new Promise( resolve =>{setTimeout( () =>{resolve('2s的结果')},2000)})async function start(){console.log(1)let res = await p1;console.log(res);console.log(2)}start()// 1// 2s的结果// 2
经典面试题
Promise.resolve().then(() => {console.log(0);return Promise.resolve(4);}).then((res) => {console.log(res)})Promise.resolve().then(() => {console.log(1);}).then(() => {console.log(2);}).then(() => {console.log(3);}).then(() => {console.log(5);}).then(() =>{console.log(6);})// 0// 1// 2// 3// 4// 5// 6/*Js引擎为了让microtask尽快的输出,做了一些优化,连续的多个then(3个)如果没有reject或者resolve会交替执行then而不至于让一个堵太久完成用户无响应,不单单v8这样其他引擎也是这样,因为其实promuse内部状态已经结束了。这块在v8源码里有完整的体现来自:https://juejin.cn/post/6945319439772434469#heading-31*/
