Promise的前提概念
Promise是一个构造函数,用来生成Promise实例Promise
构造函数承受一个函数作为参数,该函数有两个参数,别离是resolve
和reject
resolve:胜利时的回调
reject:失败时的回调
Promise别离有三个状态
1、pending :进行中
2、fulfilled:已胜利
3、rejected:已失败
Promise的执行Promise
一旦新建后就会立马执行,无奈中途勾销,Promise
返回的只有两种状态,并且该状态产生就无奈更改。也就是说Promise
的状态只有以下两种状况:
1、从pending
到fulfilled
2、从pending
到rejected
pending
的状态一旦扭转,就不会再发生变化。
Promise的后果返回Promise
外部后果一旦返回,resolve
或reject
其中的任何一种,即可产生回调。
1、resolve
的回调在then()
中获取(胜利的回调)
2、reject
的回调在cathc()
中获取(失败,捕捉谬误)
let promise = new Promise(function(resolve,reject){ // sth... let i = 5; if( i > 1){ resolve(i) // 胜利 } else { reject(error) // 失败 }}) promise.then(el=>{ // el即为resolve的参数 console.log(el); // 5 }) .catch(err=>{ console.log(err); })
Promise的执行程序Promise
创立后会立马执行,then()
是一个异步回调,将在所有的同步工作执行完后执行then()
,也就是说:Promise
在新建的时候会立刻执行,then()
或catch()
为异步工作,当所有同步工作执行完后才会执行then()
let pro = new Promise(function(resolve,reject){ console.log('Promise新建'); resolve()})pro.then(el=>{ console.log('.then回调');})console.log('同步工作');
上述代码的执行后果:
1、Promise新建
2、同步工作
3、then()回调
Promise参数和执行程序
resolve
函数的参数出了能够携带正常值以外,还能够携带Promise
实例
let pro = new Promise(function(resolve,reject){let i = 10 if(i < 50){ resolve(i) } else { reject(error) }})let pro2 = new Promise(function(resolve,reject){ resolve(pro) // 参数为上一个Promise实例}) pro2.then(el=>{ console.log(el); // 10 }) .catch(err=>{ console.log(err); })
执行程序:
先执行pro
,如果pro
的状态是pending
时,pro2
则会期待执行,当pro
的状态变成resolve
或rejected
时,pro2
则会立马执行,因为pro
决定pro2
的状态,所以前面的then
变成了针对pro
Promise的嵌套执行
let p = new Promise((resolve,reject)=>{ let i = 10 if(i > 5){ resolve(i) } else { reject('pro谬误') }})let p2 = new Promise((resolve,reject)=>{ p.then(el=>{ console.log(el * 2); // 20 if(el > 6){ // 此处须要写成return resolve(el)看起来会更失常 resolve(el) console.log('我是p1的.then回调'); // 我是p1的.then回调 } else { reject('pro2谬误') } }) }) let p3 = new Promise((resolve,reject)=>{ p2.then(el=>{ if(el > 50){ resolve(el) } else { reject('pro3谬误') } })})
多个Promise
的执行程序:
新建Promise
后会立马执行,先执行Promise
内的工作,执行实现后再执行then()
如果Promise
内有其它Promise
的then()
工作执行(这里简称p2
),会先将p2
的then()
工作执行结束,再执行本身的then()
工作
多个Promise
并行,会先按程序执行Promise
的工作,再别离依照程序别离执行他们的then()
工作
须要留神
的是:下面p2
的Promse
中,失常来说,resolve
或reject
执行完后,Promise
的使命应该实现,但此处因为执行程序的问题,并没有先执行resolve
,而是执行了console
的工作,因该写成return resolve(value)
的模式,让Promise
更失常一些,否则会呈现不必要的意外。
Promise.prototype.then()
then
办法是定义在原型对象Promise.prototype
上的,它能够为Promise
实例增加状态扭转时的回调函数。then
有两个参数(可选):resolved
:胜利状态的回调函数rejected
:失败状态的回调函数then
返回的是一个新的Promise
实例,因而能够采纳链式写法,then()
前面还能够接then()
let p = new Promise((resolve,reject)=>{ let i = 5; if(i > 4){ resolve(i) } })p.then(el=>{ console.log('then1:'+ el); if(el > 3){ return el }}).then(el=>{ console.log('then2:'+ el * 2);}).catch(err=>{ console.log(err);} /* 输入后果: then1:5 then2:10*/
下面代码应用then
办法,第一个then()
回调函数执行完后,会将返回后果传入第二个回调函数,也就是说,第二个then()
的参数是第一个then()
返回的后果。catch
的捕捉具备冒泡性质,也就是说,后面不管.then
了多少次,外面产生的谬误,都会被最初一个catch
捕捉到。
Promise.prototype.catch()
Promise.prototype.catch()
办法是.then(null,rejection)
的别名,也就是说,catch
其实是用来指定产生谬误时的回调函数。
let p = new Promise((resolve,reject)=>{ reject('错误信息') }) p.then(el=>{ // sth... }).catch(err=>{ console.log(err); // 错误信息 })
上述代码中,p
办法返回Promise
对象,该对象返回的是reject
,then()
办法调用回调函数,then()
有两个参数,一个resolved
和rejected
,如果Promise
返回的是reject
,那么.then
的状态就会变成rejected
,rejected
会调用catch()
办法指定的回调函数,解决该谬误,catch
的参数就是reject
抛出的错误信息。
如果then运行中抛出谬误,也会被catch()捕捉
let p2 = new Promise((resolve,reject)=>{ resolve(100) })p2.then(el=>{ throw new Error('then抛错')}).catch(err=>{ console.log(err); // Error: then抛错})
catch捕获谬误的形式
// 形式一let promise = new Promise(function(resolve,reject){ try { throw new Error('形式一谬误') } catch(e){ reject(e) }})promise.catch(err=>{ console.log(err); // 形式一谬误 })
// 形式二let promise2 = new Promise(function(resolve,reject){ reject(new Error('形式二谬误'))})promise2.catch(err=>{ console.log(err); // 形式二谬误 })
// 形式三let promise3 = new Promise((resolve,reject)=>{ reject('形式三谬误') }) promise3.catch(err=>{ console.log(err); // 形式三谬误 })
以上三种成果是一样的,前两种通过Error
抛出异样,后一种间接抛出异样catch
返回的也是一个Promise
对象,前面还能够接着调用then()
办法
如果Promise
的状态变成resolved
,那么再抛出谬误是有效的,因为Promise
的状态一旦产生扭转,就会永恒放弃该状态。
执行阻塞问题Promise
外部谬误不会影响到到异步队列中的Promise
内部代码,同步代码还是会造成阻塞
let p3 = new Promise((resolve,reject)=>{ resolve(str) // ReferenceError: str is not defined})p3.then(el=>{console.log(el)})setTimeout(()=>{console.log('Promise内部代码')},1000) // Promise内部代码console.log('同步代码'); // 未打印
Promise
在建设时会立刻执行,此处报错了,所以前面的同步代码都无奈执行,然而异步的setTimeout
还是会执行,并不受影响。
finally()
finally
有最初、终于的意思,也就是说finally()
办法不论Promise
最初的状态如何,都会执行
let p = new Promise((resolve,reject)=>{ resolve('东方不败')})p.then(el=>{ console.log(el); // 东方不败}).catch(err=>{ console.log(err);}).finally(()=> console.log('finally执行') // finally执行)
上述代码中,不论Promise
最初的状态怎么样,finally
都会执行,即便没有then()
和catch()
,finally
也会执行
须要留神的是,finally
不承受任何参数,然而finally
的执行程序跟外部是否是一个函数无关,如果finally
外部是一个函数,那么finally
会在Promise
最初执行,如果finally
外部没有任何函数,间接输入,那么finally
会在Promise
最后面执行。
finally
的执行跟Promise
的状态无关。
Promise.all()
Promise.all()
办法用于将多个Promise
实例包装成一个新的Promise
实例
语法:let p = Promise.all([p1,p2,p3])
let p = new Promise((resolve,reject)=>{ resolve(10)})p.then(el=>{ console.log(el);}) let p2 = new Promise((resolve,reject)=>{ // resolve(20) reject(20)})p2.then(el=>{ console.log(el);}).catch(err=>{console.log('p2:',err);})// p、p2都返回resolve则触发该函数Promise.all([p,p2]) .then(el=>{ console.log(el); }) .catch(err=>{console.log('all:',err);}) // all:20
当Promise.all
的两个promise
参数状态都变成fulfilled
时,才会触发Promise.all()
的办法,如果其中以一个参数被rejected
,那么Promise.all()
也会变成rejected
的状态,会被catch
捕获。
下面代码中,如果p2
没有chach
办法,则会调用Promise.all()
的catch
race()
Promise.race()
办法能够将多个Promise
实例包装成一个新的Promise
实例。
语法: let p = Promise.race([p1,p2,p3])
let p = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve('p1状态') },2000) }) let p2 = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve('p2状态') },1000) }) let p3 = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve('p3状态') },3000) }) let p4 = new Promise((resolve,reject)=>{ setTimeout(()=>{ reject('reject:p4状态') },4000) })let promise = Promise.race([p,p2,p3,p4])promise.then(el=>{ console.log(el); // p2状态}).catch(err=>{ console.log(err);})
race
有竞争,角逐的意思,该办法其实就是参数中,哪一个Promise
的状态先产生扭转,就调用先产生扭转的promise
,这个el
就是最先产生扭转的promise
的返回值。
Promise.allSettled()
Promise.allSettled()
办法能够在所有异步操作都完结的状况下,调用该办法。它与Promise.all()
办法不同的是,all()
办法须要所有异步都胜利才会进入then()
,而allSettled()
不须要。
let p = new Promise((resolve,reject)=>{ resolve('p1状态')}) let p2 = new Promise((resolve,reject)=>{ setTimeout(()=>{ reject('p2状态') },3000)})Promise.allSettled([p,p2]).then(el=> console.log(el) )
Promise.allSettled()
的参数不论是reject
还是resolve
都会触发,只有参数的状态全都产生扭转即可,下面代码中,p2
提早了3s
状态才产生扭转,那么Promise.allSettled()
则会期待参数的状态全都产生扭转时触发。
Promise.any()
Promise.any()
办法承受一组Promise
实例作为参数,包装成一个新的Promise
实例返回。
let p = new Promise((resolve,reject)=>{ resolve('p1状态')}) let p2 = new Promise((resolve,reject)=>{ reject('p2状态')})Promise.any([p,p2]) .then(el=>{ console.log('then:',el); // then: p1状态 }) .catch(err=>{ console.log('catch:',err); })
只有有一个参数的状态变成fulfilled
,Promise.any
就会变成fulfilled
状态
如果所有的参数实例都变成rejected
状态,包装实例才会变成rejected
状态
也就是说,any
是只有有一个参数胜利,any
就能够then
,所有参数都reject
,any
才会catch
Promise.resolve()
Promise.resolve()
能够将现有对象转为Promise
对象,Promise.resolve()
办法就起到这个作用。
语法:let p = Promise.resolve(obj)
let p = Promise.resolve('obj')p.then(el=> console.log(el)) // obj// 其实相当于let p2 = new Promise(resolve=>resolve('obj'))
如果Promise.resolve()
没有参数,那么将间接返回resolved
状态的Promise
对象,并且是一个没有参数的then()
办法。
let p3 = Promise.resolve()p3.then(el=>{ console.log(el); // undefined})setTimeout(()=>{ console.log('定时器');},0)Promise.resolve() .then(()=>{ setTimeout(()=>{console.log('resolve内定时器')},0) console.log('resolve外部'); })console.log('内部');
Promise
的执行程序,Promise
是一个异步的微工作,同步工作执行完后才会执行异步工作,异步的微工作会先执行,微工作执行完后才会执行异步的宏工作,此处的setTimeout
是异步的宏工作,所以会最初执行,内部的定时器是异步的宏工作,Promise
外部的定时器是异步微工作内的宏工作,所以微工作内的宏工作会更慢执行,此处的执行程序为:内部、resolve
外部、定时器、resolve
内定时器。
Promise.reject()
Promise.reject()
返回一个新的Promise
实例,该实例的状态为rejected
let p = Promise.reject('错误信息')p.catch(err=>console.log(err))// 等同于let p2 = new Promise((resolve,reject)=>{ reject('错误信息2')})p2.catch(err=>console.log(err))
Promise.try()
理论开发中,会遇到这么一种状况,不论函数是同步还是异步的,都想用Promise
来解决它,因为这样就能够用then()
指定下一步流程,catch
解决抛出的谬误,更便于管理流程。
基于Promise
咱们能够用async
做到同步的代码格调执行异步操作,当初有一个最新的提案,应用Promise.try()
来捕捉所有的同步和异步谬误。
为什么这么做?Promise
抛出的谬误,catch
能够捕捉到,但此处仅限于以后Promise
的异样谬误,也就是异步的。如果同步谬误抛出,那么catch()
是捕获不到的,须要在外层再嵌套一层try...catch
,这样写起来十分麻烦,代码如下:
try { let p = new Promise((resolve,reject)=>{ reject('异步谬误') }) p.catch(err=> void console.log(err) ) // 异步谬误 throw Error('同步谬误') } catch (e) { console.log(e); // 同步谬误}// 这样catch两次,能够解决同步和异步的抛错问题
如果应用Promise.try()
就能够捕捉所有的同步和异步谬误
Promise.try(()=>{ let p2 = new Promise((resolve,reject)=>{ reject('异步谬误2') }) throw Error('同步谬误2') }) .then(el=>{ console.log('then:',el); }) .catch(err=>{ console.log('catch:',err); })
此处的Promise.try
就相当于try
代码块,Promise.catch
就相当于catch
代码块。
案例源码:https://gitee.com/wang_fan_w/es6-science-institute
如果感觉这篇文章对你有帮忙,欢送点亮一下star哟