# Promise
Promise/A+ 规范 (opens new window)
# 手动实现简易版
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
function myPromise(fn) {
this.state = PENDING
this.value = null
this.resolveFuns = []
this.rejectFuns = []
const resolved = (v) => {
setTimeout(() => {
if (this.state === PENDING) {
this.state = RESOLVED
this.value = v
this.resolveFuns.forEach(fun => fun(this.value))
}
}, 0)
}
const rejected = (err) => {
setTimeout(() => {
if (this.state === PENDING) {
this.state = REJECTED
this.value = err
this.rejectFuns.forEach(fun => fun(this.value))
}
}, 0)
}
try {
fn(resolved, rejected)
} catch (err) {
rejected(err)
}
}
myPromise.prototype.then = function (resolveFun, rejectFun) {
resolveFun = typeof resolveFun === 'function' ? resolveFun : v => v
rejectFun = typeof rejectFun === 'function' ? rejectFun : err => {
throw err
}
if (this.state === PENDING) {
this.resolveFuns.push(resolveFun)
this.rejectFuns.push(rejectFun)
}
if (this.state === resolveFun) {
resolveFun(this.value)
}
if (this.state === rejectFun) {
rejectFun(this.value)
}
}
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
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
使用示例
new myPromise((resolve, reject) => {
console.log('123') // 123
// resolve(666)
reject(777)
}).then(res => {
console.log('success:' + res) // 666
}, err => {
console.log('error:' + err) // 777
})
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 符合A+规范
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
function myPromise(fn) {
this.state = PENDING
this.value = null
this.resolveFuns = []
this.rejectFuns = []
const resolved = (v) => {
if (v instanceof myPromise) {
return v.then(resolved, rejected)
}
setTimeout(() => {
if (this.state === PENDING) {
this.state = RESOLVED
this.value = v
this.resolveFuns.forEach(fun => fun(this.value))
}
}, 0)
}
const rejected = (err) => {
setTimeout(() => {
if (this.state === PENDING) {
this.state = REJECTED
this.value = err
this.rejectFuns.forEach(fun => fun(this.value))
}
}, 0)
}
try {
fn(resolved, rejected)
} catch (err) {
rejected(err)
}
}
function resolutionProcedure(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('Error'))
}
if (x instanceof MyPromise) {
x.then(function (value) {
resolutionProcedure(promise2, value, resolve, reject)
}, reject)
}
let called = false
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then
if (typeof then === 'function') {
then.call(
x,
y => {
if (called) return
called = true
resolutionProcedure(promise2, y, resolve, reject)
},
e => {
if (called) return
called = true
reject(e)
}
)
} else {
resolve(x)
}
} catch (e) {
if (called) return
called = true
reject(e)
}
} else {
resolve(x)
}
}
myPromise.prototype.then = function (resolveFun, rejectFun) {
resolveFun = typeof resolveFun === 'function' ? resolveFun : v => v
rejectFun = typeof rejectFun === 'function' ? rejectFun : err => {
throw err
}
let that = this
if (this.state === PENDING) {
return (promise2 = new myPromise((resolve, reject) => {
that.resolveFuns.push(() => {
try {
const res = resolveFun(that.value)
resolutionProcedure(promise2, res, resolve, reject)
} catch (err) {
reject(err)
}
})
that.rejectFuns.push(() => {
try {
const res = rejectFun(that.value)
resolutionProcedure(promise2, res, resolve, reject)
} catch (err) {
reject(err)
}
})
}))
}
if (this.state === RESOLVED) {
return (promise2 = new myPromise((resolve, reject) => {
setTimeout(() => {
try {
const res = resolveFun(that.value)
resolutionProcedure(promise2, res, resolve, reject)
} catch (err) {
reject(err)
}
}, 0)
}))
}
if (this.state === REJECTED) {
return (promise2 = new myPromise((resolve, reject) => {
setTimeout(() => {
try {
const res = rejectFun(this.value);
resolutionProcedure(promise2, res, resolve, reject)
} catch (err) {
reject(err)
}
}, 0)
}))
}
}
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
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
使用示例
new myPromise((resolve, reject) => {
console.log('123')
resolve(666)
// reject(777)
}).then(res => {
console.log('success:' + res)
}, err => {
console.log('err:' + err)
})I
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9