Promise, “一诺千金”,异步编程的解决方案
介绍
ES6中的原生内置对象,用来更加优雅地书写复杂的异步任务的代码
promise有三个状态, pending(进行中), fulfilled(成功), rejected(失败)。其状态不受外界影响,只要有异步操作的结果,可以决定当前是什么状态,其他任何操作都无法改变。另外,状态一旦发生变化,就不会再变
状态转换如图所示
基本使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| const p1 = new Promise((resolve, reject) => { resolve('123') })
p1.then( (res) => { console.log(res) }, (err) => { console.log(err) } )
const p2 = new Promise((resolve, reject) => { throw new Error('error_test') })
p2.then(res=> { console.log(p2) console.log(res) }).catch(err => { console.log(p2) console.log(err) })
|
方法
promise.prototype.then()
Promise实例具有then方法, 起作用就是为Promise实例添加状态改变时的回调函数。
then方法有两个参数,结构为 then((res) => {}, (err) => {})
, 这两个参数均为可选, 通常我们不会采用这样的方式,而是将成功和失败的回调分别放入到then和catch中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| const p1 = new Promise((resolve, reject) => { resolve(123) })
p1.then((res) => { console.log(res) }, (err) => { console.log(err) })
p1.then((res) => { console.log(res) }).catch((err) => { console.log(err) })
|
then方法返回值问题
如没有设置返回,或者return一个普通的值或者对象,则返回一个fulfilled状态的promise,
若return 一个promise , 则then方法也返回一个promise,状态和其一致,但不是同一个对象
这样的特性可以实现链式调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| const r1 = p1.then() console.log(r1)
const r2 = p1.then((res) => { return 456 return {name: 'coder', age: 18} })
console.log(r2) r2.then(res => { console.log(res) })
const p_pending = new Promise((resolve, reject) => {}) const r3_1 = p1.then((res) => { return p_pending }) console.log(r3_1, r3_1 == p_pending)
const p_resolved = Promise.resolve('promise resolve') const r3_2 = p1.then((res) => { return p_resolved }) console.log(r3_2, r3_2 == p_resolved) r3_2.then(res => { console.log(res) }).catch(err => { console.log(err) })
const p_rejected = Promise.reject('promise rejected') const r3_3 = p1.then(res => { return p_rejected }) console.log(r3_3, r3_3 == p_rejected) r3_3.then(res => { console.log(res) }).catch(err => { console.log(err) })
|
promise.prototype.catch()
catch((err) => {})
是then(null, (err) => {})
的别名, 当状态由pending变为rejected时,发生的回调
1 2 3 4 5 6 7
| const p1 = new Promise((resolve, reject) => { reject(123) })
p1.catch((err) => { console.log(err) })
|
catch方法返回值问题
由于其本质是then,所以返回值上面说的then方法返回值是一样的
这里就不再赘述了。 注意一点, 一定写捕获的方法体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| const p1 = new Promise((resolve, reject) => { reject(123) })
const r1 = p1.catch((err) => { console.log(err) })
console.log(r1)
const r2 = p1.catch((err) => { return 456 return {name: 'coder', age: 18} })
console.log(r2) r2.then(res => { console.log(res) })
const p_pending = new Promise((resolve, reject) => {}) const r3_1 = p1.catch((err) => { return p_pending }) console.log(r3_1, r3_1 == p_pending)
const p_resolved = Promise.resolve('promise resolve') const r3_2 = p1.catch((err) => { return p_resolved }) console.log(r3_2, r3_2 == p_resolved) r3_2.then(res => { console.log(res) }).catch(err => { console.log(err) })
const p_rejected = Promise.reject('promise rejected') const r3_3 = p1.catch(err => { return p_rejected }) console.log(r3_3, r3_3 == p_rejected) r3_3.then(res => { console.log(res) }).catch(err => { console.log(err) })
|
promise.prototype.finally()
不管promise最后状态是什么,都会执行的操作, ES2018引入的
finally() 接受一个回调函数, 回调函数中没有参数
1 2 3 4 5 6 7 8 9 10 11 12
| promise.finally(() => { })
promise.then((res) => { return res }, (err) => { throw err })
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const p1 = new Promise((resolve, reject) => { resolve(123) })
p1.then((res) => { console.log('then') console.log(res) }).finally(() => { console.log('finally') })
const p2 = new Promise((resolve, reject) => { reject(456) })
p2.catch((err) => { console.log('catch') console.log(err) }).finally(() => { console.log('finally') })
|
finally返回值问题
finally没有特别的返回值, 或者说,返回的是调用finally方法的对象的拷贝对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| const p1 = new Promise((resolve, reject) => { resolve(123) })
const r1 = p1.then((res) => { console.log('then') console.log(res) }).finally(() => { console.log('finally') return Promise.resolve('promise resolve') })
const p2 = new Promise((resolve, reject) => { reject(456) })
const r2 = p2.catch((err) => { console.log('catch') console.log(err) }).finally(() => { console.log('finally') return Promise.resolve('promise reject') })
const r3 = p1.finally(() => { return Promise.resolve('promise resolve') })
const r4 = p2.finally(() => { return Promise.resolve('promise reject') })
console.log(r1, r2)
console.log(r3, r4)
|
promise.resolve()
将一个对象包装成一个Promise对象, 关于返回的promise的状态,取决于参数的类型
若使用普通参数,或者不使用参数, 则返回一个fulfilled状态的promise
若参数是一个promise对象,则原封不动的返回这个对象,它是什么状态,返回的就是什么状态
若参数是一个thenable对象, 这回状态一个Promise对象,并立即调用then方法,方法返回的promise对象就是最后返回的promise
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| const p1 = Promise.resolve() p1.then(res => { console.log(p1) console.log(res) })
const p2 = Promise.resolve({name: 'coder', age: 18}) p2.then((res) => { console.log(p2) console.log(res) })
const p3_1 = Promise.resolve({then: (resolve, reject) => { resolve('thenable resolve') }}) p3_1.then((res) => { console.log(p3_1) console.log(res) })
const p3_2 = Promise.resolve({then: (resolve, reject) => { reject('thenable reject') }}) p3_2.catch((err) => { console.log(p3_2) console.log(err) })
const p_pending = new Promise((resolve, reject) => { }) const p4_1 = Promise.resolve(p_pending)
console.log(p_pending === p4_1) p4_1.then(res=> { console.log(res) }).catch(err => { console.log(err) })
const p_resolved = new Promise((resolve, reject) => { resolve('promise resolve') })
const p4_2 = Promise.resolve(p_resolved) console.log(p_resolved === p4_2) p4_2.then(res=> { console.log(res) }).catch(err => { console.log(err) })
const p_rejected = new Promise((resolve, reject) => { reject('promise reject') })
const p4_3 = Promise.resolve(p_rejected) console.log(p_rejected == p4_3) p4_3.then(res=> { console.log(res) }).catch(err => { console.log(err) })
|
Promise.reject()
创建一个rejected状态的promise, 其状态为rejected,与传入的参数无关
对于传入的参数, Promise.reject 会将其作为 失败的原因返回,在catch((err) => {})
中捕获
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| const p1 = Promise.reject() p1.then((res) => { console.log(res) }).catch((err) => { console.log(err) console.log(p1) })
const p2_1 = Promise.reject({name: 'coder', age: 18}) p2_1.then((res) => { console.log(res) }).catch((err) => { console.log(err) console.log(p2_1) })
const p2_2 = Promise.reject(new Error('error_test')) p2_2.then((res) => { console.log(res) }).catch((err) => { console.log(err) console.log(p2_2) })
const p_pending = new Promise((resolve, reject) => {}) const p3_1 = Promise.reject(p_pending) console.log(p3_1 == p_pending) p3_1.then(res => { console.log(res)
}).catch(err => { console.log(err, p_pending == err) console.log(p3_1) })
const p_resolved = Promise.resolve('promise resolve') const p3_2 = Promise.reject(p_resolved) p3_2.then(res => { console.log(res) console.log(p3_2) }).catch(err => { console.log(err, p_resolved == err) err.then((res) => { console.log(res) }) })
const p_rejected = Promise.reject('promise reject') const p3_3 = Promise.reject(p_rejected) p3_3.then(res => { console.log(res) console.log(p3_3) }).catch(err => { console.log(err, p_rejected == err) err.catch((i_err) => { console.log(i_err) }) })
|
Promise.all()
Promise.all()将多个Promise实例包装成一个Promise,
其接受一个promise实例的数组,返回的Promise实例,它的状态改变规则如下:
只有当数组中的所有实例状态都变为fulfilled,其状态才会改为fulfilled状态,并将所有promise实例的结果作为一个数组返回
当其中存在promise返回值为rejected, 其状态就为rejected, 第一个被rejected的实例的返回值,会被传给Promise实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| const p1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('promise p1 resolve') }, 1000) })
const p2 = new Promise((resolve, reject) => { setTimeout(() => { resolve('promise p2 resolve') }, 1200) })
const p3 = new Promise((resolve, reject) => { setTimeout(() => { resolve('promise p3 resolve') }, 1500) })
const p4 = new Promise((resolve, reject) => { setTimeout(() => { reject('promise p4 reject') }, 1300) }) const p5 = new Promise((resolve, reject) => { setTimeout(() => { reject('promise p5 reject') }, 1000) })
const p_all1 = Promise.all([p1, p2, p3]) p_all1.then((res) => { console.log(res) console.log(p_all1) }).catch(err => { console.log(err) console.log(p_all1) })
const p_all2 = Promise.all([p1, p3, p4, p5]) p_all2.then((res) => { console.log(res) console.log(p_all2) }).catch(err => { console.log(err) console.log(p_all2) })
const p6 = new Promise((resolve, reject) => { setTimeout(() => { reject('promise p6 reject') }, 800) }).catch(err => { console.log(err) })
const p_all3 = Promise.all([p1, p3, p6]) p_all3.then((res) => { console.log(res) console.log(p_all3) }).catch(err => { console.log(err) console.log(p_all3) })
|
Promise.race()
这个方法也是将多个实例,包装成一个Promise实例. 和Promise.all的区别在于,Promise.race更关心哪一个实例先执行完成(无论状态)
多一个实例中,只要有一个实例先完成,则最后返回的实例,就是这个实例的状态和值. race, 竞争,只关注第一个状态改变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| const p1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('promise p1 resolve') }, 1000) })
const p2 = new Promise((resolve, reject) => { setTimeout(() => { resolve('promise p2 resolve') }, 1200) })
const p3 = new Promise((resolve, reject) => { setTimeout(() => { reject('promise p3 reject') }, 1100) })
const p4 = new Promise((resolve, reject) => { setTimeout(() => { reject('promise p4 reject') }, 800) })
const p_race1 = Promise.race([p1, p2, p3]) p_race1.then((res) => { console.log(res) console.log(p_race1, p_race1 == p1) }).catch(err => { console.log(err) })
const p_race2 = Promise.race([p1, p2, p4]) p_race2.then((res) => { console.log(res) }).catch(err => { console.log(err) console.log(p_race2, p_race2 == p4) })
|
Promise.any()
这个也是将多个实例包装成一个Promise实例,和Promise.all 的区别在于,这个只需要其中一个实例是fulfilled,最后返回的实例就是fulfilled, 若所有实例是rejected, 则最后返回的就是一个rejected的promise, 参数是一个 AggregateError 实例,它相当于一个数组,每个成员对应一个被rejected的操作所抛出的错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| const p1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('promise p1 resolve') }, 1000) })
const p2 = new Promise((resolve, reject) => { setTimeout(() => { resolve('promise p2 resolve') }, 1200) })
const p3 = new Promise((resolve, reject) => { setTimeout(() => { reject('promise p3 reject') }, 1100) })
const p4 = new Promise((resolve, reject) => { setTimeout(() => { reject('promise p4 reject') }, 800) })
const p_any1 = Promise.any([p1, p3]) p_any1.then(res => { console.log(res) }).catch(errs => { console.log(errs) })
const p_any2 = Promise.any([p3, p4]) p_any2.then(res => { console.log(res) }).catch(results => { console.log(results, results instanceof AggregateError) console.log(results.errors) })
|
Promise.allSettled()
将一组实例包装成一个promise实例。只有等到所有这些参数实例都返回结果,不管是fulfilled还是rejected,包装实例才会结束。返回的promise是fulfilled状态,参数为所有实例的状态和值构成的对象的是一个数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| const p1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('promise p1 resolve') }, 1000) })
const p2 = new Promise((resolve, reject) => { setTimeout(() => { reject('promise p2 rejected') }, 1000) })
const p3 = new Promise((resolve, reject) => { setTimeout(() => { reject('promise p3 rejected') }, 1000) })
const p_allSettled1 = Promise.allSettled([p1, p2]) const p_allSettled2 = Promise.allSettled([p2, p3])
p_allSettled1.then((res) => { console.log(res) })
p_allSettled2.then((res) => { console.log(res) })
|