Promise
总览
Promise知识点总结
# 传统异步与回调
function fn(count, successCallback, failCallback) {
// 异步任务
setTimeout(() => {
if (count > 0) {
console.log("fn rio");
let num = 0;
for (let i = 0; i < count; i++) {
num += i;
}
// 回调函数
successCallback(num)
} else {
// 回调函数
failCallback("参数值有问题")
}
}, 2000);
}
fn(
-5,
(value) => {console.log("success " + value)}, // 在创建时就指定对应的回调函数
(err) => {console.log("fail " + err)} // 在创建时就指定对应的回调函数
)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
传统异步回调函数必须在创建时就指定对应的回调函数,而Promise可以在主体main函数中异步操作执行完毕后拿到结果并保存起来,此时结果不会消失,可以在任意时刻使用结果和指定回调函数并执行,回调函数的指定时机更灵活
# Promise异步处理
Executor是在创建Promise时需要传入的一个回调函数,这个回调函数会被立即执行,也就是传递给 new Promise
的函数被称为 executor。当 new Promise
被创建,executor 会自动运行。
它的参数 resolve
和 reject
是由 JavaScript 自身提供的回调。
当 executor 获得了结果,它应该调用以下回调之一:
resolve(value)
—— 如果任务成功完成并带有结果value
。reject(error)
—— 如果出现了 error,error
即为 error 对象。
executor 会自动运行并尝试执行一项工作。尝试结束后,如果成功则调用 resolve
,如果出现 error 则调用 reject
。
由 new Promise
构造器返回的 promise
对象具有以下内部属性:
state
—— 最初是"pending"
,然后在resolve
被调用时变为"fulfilled"
,或者在reject
被调用时变为"rejected"
。result
—— 最初是undefined
,然后在resolve(value)
被调用时变为value
,或者在reject(error)
被调用时变为error
。
const p = new Promise((resolve,reject)=>{
setTimeout(()=>{
const time = Date.now()
if (time % 2 == 0) {
resolve('成功'+time)
} else{
reject('失败'+time)
}
},1000)
})
p.then(
value => {
console.log('成功的回调: ',value);
},
reason =>{
console.log('失败的回调: ',reason);
}
)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
executor 只能调用一个 resolve
或一个 reject
。任何状态的更改都是最终的。所有其他的再对 resolve
和 reject
的调用都会被忽略
# resolve接收的参数
当resolve传入一个普通的值或者对象,那么这个值会作为then回调的参数;
当resolve里的参数是一个promise对象时,当前promise的状态由传入的promise决定
当resolve中传入的是一个对象,并且这个对象有实现then方法,那么会执行该then方法,并且根据then方法的结果来决定Promise的状态
//待传入的promise对象
const p1 = new Promise((resolve,reject)=>{
setTimeout(() => {
resolve('p1 resolve ')
}, 2000);
})
//待传入的obj对象
const obj = {
name: 'rio',
then:function(resolve){
resolve('obj resolve')
}
}
const p = new Promise((resolve,reject)=>{
console.log('a');
// resolve(p1) // a b 成功的回调: p1 resolve
resolve(obj) // a b 成功的回调: obj resolve
console.log('b');
})
p.then(
value => {
console.log('成功的回调: ',value);
},
reason =>{
console.log('失败的回调: ',reason);
}
)
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
# then和catch
.then
的第一个参数是一个函数,该函数将在 promise resolved 且接收到结果后执行。
.then
的第二个参数也是一个函数,该函数将在 promise rejected 且接收到 error 信息后执行。
const p = new Promise((resolve, reject) => {
reject('aaa')
})
p.then(
value => {
console.log('成功的回调: ',value);
},
reason =>{
console.log('失败的回调: ',reason);
}
)
-----------------------------------------------
p.then(value => {
console.log('成功的回调: ', value);
}).catch(err => {
console.log('失败的回调: ', err);
})
-----------------------------------------------
const p = new Promise((resolve, reject) => {
reject('aaa')
})
p.catch(err=>{
console.log(err);
}).catch(err=>{
console.log('err');
}).then(res=>{
console.log('res');
})
// aaa res
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
# then的返回值与链式调用
then是有返回值的,它的返回值是一个Promise
const p = new Promise((resolve, reject) => {
resolve('a')
})
const p1 = new Promise((resolve,reject)=>{
setTimeout(() => {
resolve('p1 resolve')
}, 2000);
})
p.then(res=>{
console.log(res);
return 'b'
}).then(res=>{
console.log(res);
return p1
}).then(res=>{
console.log(res);
}).catch()
// a b p1 resolve
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# finally回调
finally方法是不接收参数的,无论Promise对象无论变成fulfilled还是rejected状态,最终都会被执行
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p1 resolve')
}, 1000);
})
p1.then(res=>{
console.log(res);
}).catch(err=>{
console.log(err);
}).finally(()=>{
console.log('finally');
})
2
3
4
5
6
7
8
9
10
11
12
13
# 手写Promise
class MyPromise {
state = 'pending' // 状态
value = undefined // 成功后的值
reason = undefined // 失败后的原因
resolveCallbacks = [] // pending状态下 成功的回调
rejectCallbacks = [] // pending状态下 失败的回调
constructor(fn) {
const resolveHandler = value => {
if (this.state === 'pending') {
this.state = 'fulfilled'
this.value = value
this.resolveCallbacks.forEach(fn => fn(this.value))
}
}
const rejectHandler = reason => {
if (this.state === 'pending') {
this.state = 'rejected'
this.reason = reason
this.rejectCallbacks.forEach(fn => fn(this.reason))
}
}
try {
fn(resolveHandler, rejectHandler)
} catch (error) {
rejectHandler(error)
}
}
then(fn1, fn2) {
fn1 = typeof fn1 === 'function' ? fn1 : v => v
fn2 = typeof fn2 === 'function' ? fn2 : e => e
if (this.state === 'pending') {
const pn = new MyPromise((resolve, reject) => {
this.resolveCallbacks.push(()=>{
try {
const newValue = fn1(this.value)
resolve(newValue)
} catch (error) {
reject(error)
}
})
this.rejectCallbacks.push(()=>{
try {
const newReason = fn2(this.reason)
reject(newReason)
} catch (error) {
reject(error)
}
})
})
return pn
}
if (this.state === 'fulfilled') {
const pn = new MyPromise((resolve, reject) => {
try {
const newVal = fn1(this.value)
resolve(newVal)
} catch (error) {
reject(err)
}
})
return pn
}
if ((this.state = 'rejected')) {
const pn = new MyPromise((resolve, reject) => {
try {
const newReason = fn2(this.reason)
reject(newReason)
} catch (error) {
reject(error)
}
})
return pn
}
}
catch(fn) {
return this.then(null, fn)
}
}
MyPromise.resolve = function (value) {
return new MyPromise((resolve, reject) => resolve(value))
}
MyPromise.reject = function (reason) {
return new MyPromise((resolve, reject) => reject(reason))
}
// test
const p = new MyPromise((res, rej) => {
res(100)
})
console.log(p);
const p1 = p.then(data => {
return data + 1
})
console.log(p1);
const p2 = p1.then(data => {
return data + 2
})
console.log(p2);
const p3 = p2.catch(err => console.error(err))
console.log(p3);
const pr = MyPromise.resolve(200)
console.log(pr);
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# all方法
它的作用是将多个Promise包裹在一起形成一个新的Promise;新的Promise状态由包裹的所有Promise共同决定:
当所有的Promise状态变成fulfilled状态时,新的Promise状态为fulfilled,并且会将所有Promise的返回值组成一个数组;
当有一个Promise状态为reject时,新的Promise状态为reject,并且会将第一个reject的返回值作为参数;
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p1 resolve')
}, 1000);
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p2 resolve')
}, 5000);
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p3 resolve')
// reject('p3 rejected')
}, 3000);
})
Promise.all([p1,p2,p3]).then(res=>{
console.log('all promise:' + res);
}).catch(err=>{
console.log('promise err:' + err);
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
缺陷:当有其中一个Promise变成reject状态时,新Promise就会立即变成对应的reject状态。那么对于resolved的,以及依然处于pending状态的Promise,获取不到对应的结果
手写实现all方法
MyPromise.all = function (promiseList = []) {
const p = new MyPromise((resolve, reject) => {
const result = []
const length = promiseList.length
let resolveCount = 0
promiseList.forEach(p => {
p.then(data => {
result.push(data)
resolveCount++
if (resolveCount === length) {
resolve(result)
}
}).catch(err => reject(err))
})
})
return p
}
const pr1 = MyPromise.resolve(200)
const pr2 = MyPromise.resolve(400)
const pr22 = MyPromise.reject(400)
const pr3 = MyPromise.resolve(600)
const pr5 = MyPromise.all([pr1, pr2, pr3])
console.log('pr5', pr5);
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
# allSettled方法
该方法会在所有的Promise都有结果(settled),无论是fulfilled,还是rejected时,才会有最终的状态;并且这个Promise的结果一定是fulfilled;
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p1 resolve')
}, 1000);
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p2 resolve')
}, 5000);
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve('p3 resolve')
reject('p3 rejected')
}, 3000);
})
Promise.allSettled([p1,p2,p3]).then(res=>{
console.log('all promise:',res);
}).catch(err=>{
console.log('promise err:',err);
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# race方法
表示多个Promise相互竞争,谁先有结果,那么就使用谁的结果;
// 手写实现race
MyPromise.race = function (promiseList = []) {
let resolved = false
const p = new MyPromise((resolve, reject) => {
promiseList.forEach(p => {
p.then(data => {
if (!resolved) {
resolve(data)
resolved = true
}
}).catch(err => {
reject(err)
})
})
})
return p
}
const pr1 = MyPromise.resolve(200)
const pr2 = MyPromise.resolve(400)
const pr22 = MyPromise.reject(400)
const pr3 = MyPromise.resolve(600)
const pr6 = MyPromise.race([pr1, pr2, pr3])
console.log('pr6', pr6);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# any方法
会等到一个fulfilled状态,在决定新Promise的状态;如果所有的Promise都是reject的,那么会等到所有的Promise都变成rejected状态;
# 参考
Promise - JavaScript | MDN (mozilla.org) (opens new window)
JavaScript高级程序设计(第4版)