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秒后得到 1
console.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)
})
// 某个状态为reject
let 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
*/