Promise介绍以及使用

Yaurora

Promise, “一诺千金”,异步编程的解决方案

介绍

ES6中的原生内置对象,用来更加优雅地书写复杂的异步任务的代码

promise有三个状态, pending(进行中), fulfilled(成功), 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
const p1 = new Promise((resolve, reject) => {
resolve('123')
})

p1.then(
(res) => {
console.log(res) // 123
},
(err) => {
console.log(err)
}
)

const p2 = new Promise((resolve, reject) => {
// 三种写法一样,都是返回一个rejected promise
throw new Error('error_test')
// resolve(new Error('error_test'))
// reject(new Error('error_test'))
})

p2.then(res=> {
console.log(p2)
console.log(res)
}).catch(err => {
console.log(p2) // rejected
console.log(err) // Error: error_test
})

方法

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)
// reject(234)
})

p1.then((res) => {
console.log(res) // 123
}, (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
// 1. 不显示设置返回值
const r1 = p1.then()
console.log(r1) // 得到的是一个值为undefined,状态为fulfilld的promise

// 2. 设置普通参数/对象
const r2 = p1.then((res) => {
return 456
return {name: 'coder', age: 18}
})

console.log(r2) // 值为then中return的参数,状态为fulfilled的参数
r2.then(res => {
console.log(res) // 456
})

// 3. promise对象
// 3.1 pending
const p_pending = new Promise((resolve, reject) => {})
const r3_1 = p1.then((res) => {
return p_pending
})
console.log(r3_1, r3_1 == p_pending) // 状态为pending的promise

// 3.2 fulfilled
const p_resolved = Promise.resolve('promise resolve')
const r3_2 = p1.then((res) => {
return p_resolved
})
console.log(r3_2, r3_2 == p_resolved) // 状态为fulfilled,值为promise resolve 的promise, 和传入的对象不是同一个
r3_2.then(res => {
console.log(res) // promise resolve
}).catch(err => {
console.log(err)
})

// 3.3 rejected
const p_rejected = Promise.reject('promise rejected')
const r3_3 = p1.then(res => {
return p_rejected
})
console.log(r3_3, r3_3 == p_rejected) // 状态为rejected, 返回值为promise rejeced的promise, 和传入参数不是同一个
r3_3.then(res => {
console.log(res)
}).catch(err => {
console.log(err) // promise rejected
})

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)
})

// 1. 不显示设置返回值
const r1 = p1.catch((err) => {
console.log(err)
})
// 若写成 const r1 = p1.catch() , 则返回一个rejected的promise
console.log(r1) // 返回一个fulfilled 状态的promise, 值为undefined

// 2. 设置普通参数/对象
const r2 = p1.catch((err) => {
return 456
return {name: 'coder', age: 18}
})

console.log(r2) // 值为catch中return的参数,状态为fulfilled的参数
r2.then(res => {
console.log(res) // 456
})

// 3. promise对象
// 3.1 pending
const p_pending = new Promise((resolve, reject) => {})
const r3_1 = p1.catch((err) => {
return p_pending
})
console.log(r3_1, r3_1 == p_pending) // 状态为pending的promise

// 3.2 fulfilled
const p_resolved = Promise.resolve('promise resolve')
const r3_2 = p1.catch((err) => {
return p_resolved
})
console.log(r3_2, r3_2 == p_resolved) // 状态为fulfilled,值为promise resolve 的promise, 和传入的对象不是同一个
r3_2.then(res => {
console.log(res) // promise resolve
}).catch(err => {
console.log(err)
})

// 3.3 rejected
const p_rejected = Promise.reject('promise rejected')
const r3_3 = p1.catch(err => {
return p_rejected
})
console.log(r3_3, r3_3 == p_rejected) // 状态为rejected, 返回值为promise rejeced的promise, 和传入参数不是同一个
r3_3.then(res => {
console.log(res)
}).catch(err => {
console.log(err) // promise rejected
})

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')
})

// 解释 由于 在调用finally之前,分别调用了 then/catch, 返回的promise就是如下状态,再次调用finally,不会返回我们想要的返回值
console.log(r1, r2) // [fulfilled, undefined] [fulfilled, undefined]

// 这里也就能理解为什么会返回p1, p2 一样的状态了
console.log(r3, r4) // [fulfilled, 123] [rejected, 456]

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
// 1. 不使用参数
const p1 = Promise.resolve()
p1.then(res => {
console.log(p1) // promise fulfilled
console.log(res) // undefined
})

// 2. 使用普通参数
const p2 = Promise.resolve({name: 'coder', age: 18})
p2.then((res) => {
console.log(p2) // fulfiled状态的promise
console.log(res) // {name: 'coder', age: 18}
})

// 3. thenable对象(含有then方法的对象)
const p3_1 = Promise.resolve({then: (resolve, reject) => {
resolve('thenable resolve')
}})
p3_1.then((res) => {
console.log(p3_1) //fulfiled状态的promise
console.log(res) // thenable resolve
})

const p3_2 = Promise.resolve({then: (resolve, reject) => {
reject('thenable reject')
}})
p3_2.catch((err) => {
console.log(p3_2) // rejected状态的promise
console.log(err) // thenable reject
})

// 4. promise对象
// 4.1 传入pending状态
const p_pending = new Promise((resolve, reject) => {
// 没有调用 resolve/ reject, 故状态为pending
})
const p4_1 = Promise.resolve(p_pending)
// 说明如参数是promise对象, 则会原封不动的返回这个参数
console.log(p_pending === p4_1) // true
p4_1.then(res=> {
console.log(res) // 没有输出
}).catch(err => {
console.log(err) // 没有输出
})

// 4.2 传入fulfilled状态
const p_resolved = new Promise((resolve, reject) => {
resolve('promise resolve')
})
// const p_resolve = Promise.resolve("promise resolve")
const p4_2 = Promise.resolve(p_resolved)
console.log(p_resolved === p4_2) // true
p4_2.then(res=> {
console.log(res) // promise resolve
}).catch(err => {
console.log(err) // 没有输出
})

// 4.3 传入rejected 状态
const p_rejected = new Promise((resolve, reject) => {
reject('promise reject')
})

const p4_3 = Promise.resolve(p_rejected)
console.log(p_rejected == p4_3) // true
p4_3.then(res=> {
console.log(res) // 没有输出
}).catch(err => {
console.log(err) // promise reject
})

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
// 1. 没有参数
const p1 = Promise.reject()
p1.then((res) => {
console.log(res) // 没有数据
}).catch((err) => {
console.log(err) // undefined
console.log(p1) // rejected
})

// 2. 普通参数或对象
const p2_1 = Promise.reject({name: 'coder', age: 18})
p2_1.then((res) => {
console.log(res) // 没有数据
}).catch((err) => {
console.log(err) // {name: 'coder', age: 18}
console.log(p2_1) // rejected
})

const p2_2 = Promise.reject(new Error('error_test'))
p2_2.then((res) => {
console.log(res) // 没有数据
}).catch((err) => {
console.log(err) // Error: error_test
console.log(p2_2) // rejected
})

// 3. Promise对象
// 3.1 pending
const p_pending = new Promise((resolve, reject) => {})
const p3_1 = Promise.reject(p_pending)
console.log(p3_1 == p_pending) // false
p3_1.then(res => {
console.log(res)

}).catch(err => {
console.log(err, p_pending == err) // promise , true
console.log(p3_1)
})

// 3.2 fulfilled
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) // promise , true
err.then((res) => {
console.log(res) // promise resolve
})
})

// 3.3 rejected
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) // promise , true
err.catch((i_err) => {
console.log(i_err) // promise reject
})
})

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) //  ['promise p1 resolve', 'promise p2 resolve', 'promise p3 resolve']
console.log(p_all1) // { fullfiled, Array }
}).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) // promise p5 reject
console.log(p_all2) // {rejected, 'promise p5 reject'}
})

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) //  ['promise p1 resolve', 'promise p3 resolve', undefined]
console.log(p_all3) // { fullfiled, Array }
}).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) // promise p1 resolve
console.log(p_race1, p_race1 == p1) // false, 说明返回的是一个新的实例
}).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) // promise p3 reject
console.log(p_race2, p_race2 == p4) // false
})

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) // promise p1 resolve
}).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) // AggregateError: All promises were rejected
console.log(results.errors) // ['promise p3 reject', 'promise p4 reject']
})

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) // [ {status: 'fulfilled', value: 'promise p1 resolve'}, {status: 'rejected', reason: 'promise p2 rejected'}]
})

p_allSettled2.then((res) => {
console.log(res) // [ {status: 'rejected', reason: 'promise p2 rejected'}, {status: 'rejected', reason: 'promise p3 rejected'} ]
})
  • 标题: Promise介绍以及使用
  • 作者: Yaurora
  • 创建于 : 2023-03-06 09:28:51
  • 更新于 : 2023-03-10 18:47:10
  • 链接: https://jingyu.life/2023/03/06/node/promise-usage/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。