Promise
Promise的含义
Promise是异步编程的一种解决方案,比以前传统的异步操作就是回调函数和事件更强大,使用起来更简便,并且避免了回调地狱的问题(回调地狱就是指多层回调函数嵌套)
Promise是es6新增的引用类型,是一个构造函数,通过和关键字new一起使用来创建Promise实例,需要传递一个执行器函数(这个执行器函数是同步执行的),执行器函数有两个参数且都是函数,这两个参数是js提供的不需要我们手动创建
const p = new Promise((resolve,reject) => {
console.log('我是一个Promise实例')
})
console.log(p)
//
我是一个Promise实例
Promise { <pending> } 这里为什么是pending后面会讲到
Promise的三种状态
- 三种状态:
- 待定(初始)状态:
pending
; - 成功(解决)状态:
fulfilled
; - 失败(拒绝)状态:
rejected
- 待定(初始)状态:
- 状态转换
- 两种转换:
pending
---->fulfilled
;pending
----->rejected
;有且仅有这两中转换,并且状态一经变化之后就不会在变了 - 如何转换:通过new Promise初始化时执行器函数的两个参数函数 resolve(
pending
---->fulfilled
),reject(pending
----->rejected
);还可以通过静态方法Promise.resolve
和Promise.reject
来实现状态转换,下面会讲到这两中静态方法;再回到上面那个问题为什么是pending
,因为在初始化实例的时候并没有执行resolve和reject这两个当中的任意一个,所以还是处于pending
状态
- 两种转换:
new Promise 转换状态
let p = new Promise((resolve,reject) => {
resolve('成功')
})
console.log(p)
p = new Promise((resolve,reject) => {
reject('拒绝')
})
console.log(p)
//
Promise { '成功' } // 如果是成功状态则不会在结果里面标出 fulfilled
Promise { <rejected> '拒绝' }
// 下面是 reject 报错
(node:20111) UnhandledPromiseRejectionWarning: 拒绝
(Use `node --trace-warnings ...` to show where the warning was created) ....
静态方法 状态转换 pending
—> rejected
let p = new Promise((resolve, reject) => {
})
console.log(p)
p = Promise.reject('fail')
console.log(p)
//
Promise { <pending> }
Promise { <rejected> 'fail' }
pending
-----> fulfilled
let p = new Promise((resolve, reject) => {
})
console.log(p)
p = Promise.resolve('fail')
console.log(p)
//
Promise { <pending> }
Promise { 'success' }
状态一经变化后就不会在变了
p = new Promise((resolve, reject) => {
resolve('success')
reject('fail')
})
console.log(p)
//
Promise {'success'}
Promise实例方法
-
Promise.prototype.then
- 用于给Promise实例添加状态改变时回调函数
- 最多有两个参数,第一个参数:onResolved处理程序(处理
fulfilled
状态的回调函数),第二个参数:onRejected处理程序(处理rejected
状态的回调函数),由于只能转换一次,所以这两个处理程序是互斥的,只能执行一个
let fulfilled = new Promise((resolve, reject) => { resolve('success') }) let rejected = new Promise((resolve, reject) => { reject('fail') }) fulfilled.then(res => console.log('res',res), err => console.log('err',err)) rejected.then(res => console.log('res',res), err => console.log('err',err)) // res success err fail
- 只需要一个参数的写法
fulfilled.then((res) => console.log('res',res)) // // res success rejected.then(null, (err)=> console.log('err',err)) // err fail
- 函数返回值
函数返回值是一个Promise实例,但是其状态与他的调用者的状态无关,与then方法的 onResolved处理程序,onRejected处理程序的返回值有关,如果处理程序返回普通值、错误对象和
fulfilled
状态实例就会被Promise.resolve包裹成一个fulfilled
状态的实例,如果返回的是一个rejected
实例或抛出异常则返回的是一个rejected
实例处理程序返回普通值、错误对象和
fulfilled
状态实例处理程序返回
fulfilled
状态实例其实和普通值一样,只不过就是普通值还需要被包裹成一个fulfilled
状态实例才能调用下一个then// 返回一个 fulfilled 状态实例 const resolved = Promise.resolve('resolved') const p1 = resolved.then(() => Promise.resolve('yes')) setTimeout(console.log, 0, 'p1',p1) // p1 Promise { 'yes' } // 返回一个错误对象,会被包裹成一个 fulfilled 状态实例 const p3 = resolved.then(res => Error('error')) setTimeout(console.log, 0, 'p3',p3) //p3 Promise { // Error: error // at /Users/dingjie/practise/js红宝书/Promise/04实例方法then.js:14:33 // } // 返回普通值 const p5 = resolved.then(() => 'success') setTimeout(console.log, 0, p5) // Promise { 'success'}
注意:这里为什么不直接使用 console.log而是使用定时器可以参考这篇文章:js执行机制
处理程序返回
rejected
状态实例 或 抛出异常// 返回一个 rejected 状态实例 const rejected = Promise.reject('rejected') const p2 = rejected.then(undefined, () => Promise.reject('no')) setTimeout(console.log, 0, 'p2',p2) // p2 Promise { <rejected> 'no' } // 抛出一个异常,则返回一个 rejected 状态实例 const p4 = resolved.then(res => {throw 'error'}) setTimeout(console.log, 0, 'p4',p4) // p4 Promise { <rejected> 'error' }
- 链式调用
处理程序返回一个普通值会自动包裹成一个
fulfilled
状态实例,自动调用下一个then
,并且将这个普通值作为实参传递给下一个then方法的onResolved处理程序返回一个
fulfilled
状态实例,自动调用下一个then
,并且这个实例的值作为实参传递给下一个then
方法的onResolved处理程序const p = new Promise((resolve,reject) => { resolve('fulfilled') }) p.then(res => res) .then((res => 'status:' + res ),(err => console.log('err',err))) .then(res => console.log('res',res)) // res status:fulfilled
-
Promise.prototype.catch
- 只接受一个参数,onRejected处理程序用于处理
rejected
状态的回调函数
const rejected = Promise.reject('rejected') rejected.catch(res => console.log('res',res)) // res rejected
- 返回值
返回值:受 onRejected处理程序的返回值影响
const res = Promise.reject() // 返回普通值 const p1 = res.catch(() => '普通值') setTimeout(console.log, 0, p1) // Promise { '普通值' } // 返回 fulfilled 状态实例 const p2 = res.catch(() => Promise.resolve()) setTimeout(console.log, 0, p2) // Promise { undefined } // 返回 rejected 状态实例 const p3 = res.catch(() => Promise.reject()) setTimeout(console.log, 0, p3) // Promise { <rejected> undefined } // 抛出错误 const p4 = res.catch(() => {throw 'error'}) setTimeout(console.log, 0, p4) // Promise { <rejected> 'error' }
- 只接受一个参数,onRejected处理程序用于处理
-
Promise.prototype.finally
finally()
方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。常用来做清理操作,或者用来执行fulfilled
状态和rejected
状态都会执行的操作;它不接受任何参数
let p = new Promise((resolve,reject)=> { resolve(10) }) p.then(res=>console.log('resolve',res)) .catch(res => console.log('reject',res)) .finally(() => console.log('finally')) // //resolve 10 //finally p = Promise.reject('100') p.then(res=>console.log('resolve',res)) .catch(res => console.log('reject',res)) .finally(() => console.log('finally')) // //reject 100 //finally
- 返回值:始终返回原来的值(也可以理解为始终接受来自父(实例对象)的传递),除了这三种情况:返回一个
rejected
状态实例,抛出错误或异常,返回一个pending
状态实例
const p1 = Promise.resolve(10).finally(() => 1000) const p2 = Promise.resolve(10).finally(() => '10') const p3 = Promise.resolve(10).finally(() => undefined) const p4 = Promise.resolve(10).finally(() => null) const p5 = Promise.resolve(10).finally(() => Promise.resolve(1000)) const p6 = Promise.resolve(10).finally(() => false) const p7 = Promise.resolve(10).finally(() => Error('erroe')) setTimeout(console.log, 0 , 'p1',p1) setTimeout(console.log, 0 , 'p2',p2) setTimeout(console.log, 0 , 'p3',p3) setTimeout(console.log, 0 , 'p4',p4) setTimeout(console.log, 0 , 'p5',p5) setTimeout(console.log, 0 , 'p6',p6) setTimeout(console.log, 0 , 'p7',p7) // /** p1 Promise { 10 } p2 Promise { 10 } p3 Promise { 10 } p4 Promise { 10 } p5 Promise { 10 } p6 Promise { 10 } p7 Promise { 10 } */ const p8 = Promise.resolve(10).finally(() => Promise.reject('error')) const p9 = Promise.resolve(10).finally(() => {throw 'error'}) const p10 = Promise.resolve(10).finally(() => new Promise((resolve,reject) => {})) setTimeout(console.log, 0 , 'p8',p8) // p8 Promise { <rejected> 'error' } setTimeout(console.log, 0, 'p9',p9) // p9 Promise { <rejected> 'error' } setTimeout(console.log, 0, 'p10',p10) // p10 Promise { <pending> }
Promise静态方法
-
Promise.resolve
-
将一个值变成一个
fulfilled
状态的实例 -
有一个参数,可选
- 参数是一个Promise实例:原封不动的返回,可以理解为浅拷贝
const p = Promise.resolve(10) const f = Promise.reject('error') let fulfilled = Promise.resolve(p) console.log('fulfilled',fulfilled, fulfilled === p) // fulfilled Promise { 10 } true fulfilled=Promise.resolve(f) console.log('fulfilled',fulfilled, fulfilled === f) // fulfilled Promise { <rejected> 'error' } true
- 参数是一个普通值:
Promise.resolve
将这个普通值包成一个fulfilled
状态实例
let p = Promise.resolve('10') console.log(p) // Promise { '10' } p = Promise.resolve(10) console.log(p) // Promise { 10 }
- 无参数:将
undefined
包成一个fulfilled
状态实例
console.log(Promise.resolve()) // Promise { undefined }
- 参数是一个
thenable
对象:thenable
是指具有then
方法的对象;将这个thenable
对象转换成Promise对象,并且会立即调用这个then
方法,所以此时这个Promise对象的状态就由then
方法说了算,先调用resolve
那么就是fulfilled
状态实例,先调用reject
那么就是fulfilled
状态实例,哪个都不调用就是pending
状态实例
let thenable = { then(resolve,reject) { console.log('这是 thenable的then方法') resolve('success') } } let p = Promise.resolve(thenable) setTimeout(console.log, 0, p) // 这是 thenable的then方法 Promise { 'success' }
-
-
Promise.reject
-
将一个值变成一个
rejected
状态的实例- 参数是一个Promise实例:将这个 Promise 实例包裹成一个
rejected
状态实例
const r = Promise.reject('error') const f = Promise.resolve('success') console.log(Promise.reject(r)) console.log(Promise.reject(f)) // Promise { <rejected> Promise { <rejected> 'error' } } Promise { <rejected> Promise { 'success' } }
- 参数是一个普通值:Promise.reject将这个普通值包成一个
rejected
状态实例
console.log(Promise.reject('10')) console.log(Promise.reject(10)) // Promise { <rejected> '10' } Promise { <rejected> 10 }
- 无参数:将
undefined
包成一个rejected
状态实例
console.log(Promise.reject()) Promise { <rejected> undefined }
- 参数是一个
thenable
对象,同Promise.resolve
- 参数是一个Promise实例:将这个 Promise 实例包裹成一个
-
-
Promise.all
Promise.all
将一组Promise
实例(注意:Promise.all()
方法接受一个数组作为参数,数组里面每一项都应该是 Promise实例,如果不是则会自动转换成 Promise实例,Promise.all()
方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。)包装成一个新的实例,待这一组Promise实例对象状态全部变成fulfilled
状态,就会返回一个新的fulfilled
状态实例,这个新的fulfilled
状态实例存放了这一组Promise实例的结果;
let p1 = Promise.resolve(1)
let p2 = Promise.resolve(10)
let p3 = Promise.resolve(100)
let results = Promise.all([p1,p2,p3])
setTimeout(console.log,0, results)
//
Promise { [ 1, 10, 100 ] }
如果其中有任意一个
rejected
时立即结束,并返回这个 rejected 状态实例
适合彼此相互依赖或者在其中任何一个reject时立即结束。
p1 = Promise.reject('error')
results = Promise.all([p1,p2,p3])
setTimeout(console.log,0, results)
//
Promise { <rejected> 'error' }
注意,如果作为参数的 Promise 实例,自己定义了
catch
方法,那么它一旦被rejected
,并不会触发Promise.all()
的catch
方法,而是调用自己的catch
方法
p1 = new Promise((resolve, reject) => {
resolve('resolve')
}).then(res =>
res
).catch(err => err)
p2 = new Promise((resolve, reject) => {
reject('reject')
})
.then(res => res)
.catch(err => err)
result = Promise.all([p1, p2]).then(res => console.log('res-result', res)).catch(err => console.log('err-result', err))
//
res-result [ 'resolve', 'reject' ]
注意,由于p2调用来自己的 catch 方法,所以最后 p2也会变成 fulfilled 状态实例,所以
Promise.all()
方法参数里面的两个实例都会fulfilled
,因此会调用then
方法指定的回调函数,而不会调用catch
方法指定的回调函数。
- Promise.race
将多个Promise实例包装成一个Promise实例,只要其中一个状态改变了(不论是
rejected
还是fulfilled
),那么这个方法就会返回这个状态改变的Promise实例
const p1 = new Promise((resolve,reject) => {
setTimeout(() => resolve('success'), 1000)
})
const p2 = new Promise((resolve,reject) => {
setTimeout(() => reject('error'), 0)
})
const result = Promise.race([p1,p2])
setTimeout(console.log, 1500, 'result',result) // result Promise { <rejected> 'error' }
注意:如果
Promise.race
的参数是一个空数组,那么最后返回的结果是一个pending
实例
const res = Promise.race([])
setTimeout(console.log, 0, 'res',res) // res Promise { <pending> }
- Promise.allSettled
Promise.allSettled()
方法接受一个数组作为参数,数组的每个成员都是一个 Promise 对象,并返回一个新的 Promise 对象。只有等到参数数组的所有 Promise 对象都发生状态变更(不管是fulfilled
还是rejected
),返回的 Promise 对象才会发生状态变更。
当有多个彼此不依赖的异步任务成功完成时,或者总是想知道每个promise的结果时,通常使用它。
const p1 = Promise.resolve('resolve')
const p2 = Promise.resolve('reject')
let result = Promise.allSettled([p1,p2])
setTimeout(console.log, 0, result)
//
Promise {
[
{ status: 'fulfilled', value: 'resolve' },
{ status: 'fulfilled', value: 'reject' }
]
}
这个方法就返回一个新的Promise实例,并且这个实例附带了这一组Promise实例的结果,并带有一个对象数组,每个对象表示对应的promise结果。
- Promise.any(待补充)