-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpromise.js
182 lines (164 loc) · 4.68 KB
/
promise.js
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
class Promise {
constructor(executor) {
if (typeof executor !== 'function') {
throw new TypeError(`Promise resolver ${executor} is not a function`)
}
this.value = null // 终值
this.reason = null // 拒因
this.state = Promise.PENDING // 状态
this.onFulfilledCallbacks = [] // 成功回调
this.onRejectedCallbacks = [] // 失败回调
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
try {
console.log('constructor executor')
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
resolve(value) {
console.log('resolve', this.state, value)
if (this.state === Promise.PENDING) {
this.state = Promise.FULFILLED
this.value = value
this.onFulfilledCallbacks.forEach(fn => fn(this.value))
}
}
reject(reason) {
console.log('reject', this.state, reason)
if (this.state === Promise.PENDING) {
this.state = Promise.REJECTED
this.reason = reason
this.onRejectedCallbacks.forEach(fn => fn(this.reason))
}
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
then(onFulfilled, onRejected) {
console.log('then', this.state)
if (typeof onFulfilled !== 'function') {
onFulfilled = function(value) {
return value
}
}
if (typeof onRejected !== 'function') {
// 如果没有 onReject 直接抛出错误,或被catch到
onRejected = function(reason) {
throw reason
}
}
let promise2 = new Promise((resolve, reject) => {
if (this.state === Promise.FULFILLED) {
setTimeout(() => {
try {
const x = onFulfilled(this.value)
Promise.resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
if (this.state === Promise.REJECTED) {
setTimeout(() => {
try {
const x = onRejected(this.reason)
Promise.resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
if (this.state === Promise.PENDING) {
// 如果还在等待中,则将回调存起来,等待被调用
this.onFulfilledCallbacks.push((value) => {
setTimeout(() => {
try {
// 连续then调用情况下,拿到上一个then的返回值去resolve
const x = onFulfilled(value)
Promise.resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
})
this.onRejectedCallbacks.push((reason) => {
setTimeout(() => {
try {
const x = onRejected(reason)
Promise.resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
})
}
})
return promise2
}
}
Promise.PENDING = 'pending'
Promise.FULFILLED = 'fulfilled'
Promise.REJECTED = 'reject'
Promise.resolvePromise = function(promise2, x, resolve, reject) {
console.log('resolvePromise')
if (promise2 === x) {
reject(new TypeError('Chaining cycle detected for promise'))
}
let called = false // 防止resolve和reject多次调用
if (x instanceof Promise) {
// 如果x为promise,则将他执行,获取value继续resolve
x.then(value => {
Promise.resolvePromise(promise2, value, resolve, reject)
}, reason => {
reject(reason)
})
} else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
// x 为对象或函数
try {
const then = x.then
if (typeof then === 'function') { // 判断是否为thenable
then.apply(x, [
value => {
if (called) return
called = true
Promise.resolvePromise(promise2, value, resolve, reject)
},
reason => {
if (called) return
called = true
reject(reason)
}
])
} else {
if (called) return
called = true
resolve(x)
}
} catch (error) {
if (called) return
called = true
reject(error)
}
} else {
// 普通类型
resolve(x)
}
}
Promise.prototype.finally = function (callback) {
var P = this.constructor
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};
Promise.defer = Promise.deferred = function () {
let dfd = {}
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
module.exports = Promise