Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e495812

Browse files
committed
feat: promise A+
1 parent be6479f commit e495812

File tree

1 file changed

+117
-34
lines changed

1 file changed

+117
-34
lines changed

promise.js

Lines changed: 117 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -39,51 +39,55 @@ Promise.prototype.then = function(onResolved, onRejected) {
3939
var promise2
4040

4141
// 根据标准,如果then的参数不是function,则我们需要忽略它,此处以如下方式处理
42-
onResolved = typeof onResolved === 'function' ? onResolved : function(value) {}
43-
onRejected = typeof onRejected === 'function' ? onRejected : function(reason) {}
42+
// 并且默认函数需要return值 以便于空值的穿透
43+
onResolved =
44+
typeof onResolved === "function"
45+
? onResolved
46+
: function(value) {
47+
return value
48+
}
49+
onRejected =
50+
typeof onRejected === "function"
51+
? onRejected
52+
: function(reason) {
53+
return reason
54+
}
4455

45-
if (self.status === 'resolved') {
56+
if (self.status === "resolved") {
4657
// 如果promise1(此处即为this/self)的状态已经确定并且是resolved,我们调用onResolved
4758
// 因为考虑到有可能throw,所以我们将其包在try/catch块里
48-
return promise2 = new Promise(function(resolve, reject) {
59+
return (promise2 = new Promise(function(resolve, reject) {
4960
try {
5061
var x = onResolved(self.data)
51-
if (x instanceof Promise) { // 如果onResolved的返回值是一个Promise对象,直接取它的结果做为promise2的结果
52-
return x.then(resolve, reject)
53-
}
54-
resolve(x) // 否则,以它的返回值做为promise2的结果
62+
resolvePromise(promise2, x, resolve, reject)
5563
} catch (e) {
5664
reject(e) // 如果出错,以捕获到的错误做为promise2的结果
5765
}
58-
})
66+
}))
5967
}
6068

6169
// 此处与前一个if块的逻辑几乎相同,区别在于所调用的是onRejected函数,就不再做过多解释
62-
if (self.status === 'rejected') {
63-
return promise2 = new Promise(function(resolve, reject) {
70+
if (self.status === "rejected") {
71+
return (promise2 = new Promise(function(resolve, reject) {
6472
try {
6573
var x = onRejected(self.data)
66-
if (x instanceof Promise) {
67-
return x.then(resolve, reject)
68-
}
74+
resolvePromise(promise2, x, resolve, reject)
6975
} catch (e) {
7076
reject(e)
7177
}
72-
})
78+
}))
7379
}
7480

75-
if (self.status === 'pending') {
76-
// 如果当前的Promise还处于pending状态,我们并不能确定调用onResolved还是onRejected,
77-
// 只能等到Promise的状态确定后,才能确实如何处理。
78-
// 所以我们需要把我们的**两种情况**的处理逻辑做为callback放入promise1(此处即this/self)的回调数组里
79-
// 逻辑本身跟第一个if块内的几乎一致,此处不做过多解释
80-
return promise2 = new Promise(function(resolve, reject) {
81+
if (self.status === "pending") {
82+
// 如果当前的Promise还处于pending状态,我们并不能确定调用onResolved还是onRejected,
83+
// 只能等到Promise的状态确定后,才能确实如何处理。
84+
// 所以我们需要把我们的**两种情况**的处理逻辑做为callback放入promise1(此处即this/self)的回调数组里
85+
// 逻辑本身跟第一个if块内的几乎一致,此处不做过多解释
86+
return (promise2 = new Promise(function(resolve, reject) {
8187
self.onResolvedCallback.push(function(value) {
8288
try {
8389
var x = onResolved(self.data)
84-
if (x instanceof Promise) {
85-
return x.then(resolve, reject)
86-
}
90+
resolvePromise(promise2, x, resolve, reject)
8791
} catch (e) {
8892
reject(e)
8993
}
@@ -92,28 +96,107 @@ Promise.prototype.then = function(onResolved, onRejected) {
9296
self.onRejectedCallback.push(function(reason) {
9397
try {
9498
var x = onRejected(self.data)
95-
if (x instanceof Promise) {
96-
return x.then(resolve, reject)
97-
}
99+
resolvePromise(promise2, x, resolve, reject)
98100
} catch (e) {
99101
reject(e)
100102
}
101103
})
102-
})
104+
}))
105+
}
106+
}
107+
108+
/*
109+
resolvePromise函数即为根据x的值来决定promise2的状态的函数
110+
也即标准中的[Promise Resolution Procedure](https://promisesaplus.com/#point-47)
111+
x为`promise2 = promise1.then(onResolved, onRejected)`里`onResolved/onRejected`的返回值
112+
`resolve`和`reject`实际上是`promise2`的`executor`的两个实参,因为很难挂在其它的地方,所以一并传进来。
113+
相信各位一定可以对照标准把标准转换成代码,这里就只标出代码在标准中对应的位置,只在必要的地方做一些解释
114+
*/
115+
function resolvePromise(promise2, x, resolve, reject) {
116+
var then
117+
var thenCalledOrThrow = false
118+
119+
// 对应标准2.3.1节
120+
// If promise and x refer to the same object, reject promise with a TypeError as the reason.
121+
if (promise2 === x) {
122+
return reject(new TypeError("Chaining cycle detected for promise!"))
123+
}
124+
125+
// 2.3.2
126+
/**
127+
* If x is a promise, adopt its state [3.4]:
128+
If x is pending, promise must remain pending until x is fulfilled or rejected.
129+
If/when x is fulfilled, fulfill promise with the same value.
130+
If/when x is rejected, reject promise with the same reason.
131+
*/
132+
133+
if (x instanceof Promise) {
134+
// 对应标准2.3.2节
135+
// 如果x的状态还没有确定,那么它是有可能被一个thenable决定最终状态和值的 有可能x是个promise但是它resolve的又是一个promise
136+
// 比如
137+
// 所以这里需要做一下处理,而不能一概的以为它会被一个“正常”的值resolve
138+
if (x.status === "pending") {
139+
x.then(function(value) {
140+
resolvePromise(promise2, value, resolve, reject)
141+
}, reject)
142+
} else {
143+
// 但如果这个Promise的状态已经确定了,那么它肯定有一个“正常”的值,而不是一个thenable,所以这里直接取它的状态
144+
x.then(resolve, reject)
145+
}
146+
return
147+
}
148+
149+
if (x !== null && (typeof x === "object" || typeof x === "function")) {
150+
// 2.3.3
151+
try {
152+
// 2.3.3.1 因为x.then有可能是一个getter,这种情况下多次读取就有可能产生副作用
153+
// 即要判断它的类型,又要调用它,这就是两次读取
154+
then = x.then
155+
156+
if (typeof then === "function") {
157+
// 2.3.3.3
158+
then.call(
159+
x,
160+
function rs(y) {
161+
// 2.3.3.3.1
162+
if (thenCalledOrThrow) return
163+
thenCalledOrThrow = true
164+
return resolvePromise(promise2, y, resolve, reject) // 2.3.3.3.1
165+
},
166+
function rj(r) {
167+
if (thenCalledOrThrow) return // 2.3.3.3.3 即这三处谁选执行就以谁的结果为准
168+
thenCalledOrThrow = true
169+
return reject(r)
170+
},
171+
)
172+
} else {
173+
resolve(x)
174+
}
175+
} catch (e) {
176+
if (thenCalledOrThrow) return // 2.3.3.3.3 即这三处谁选执行就以谁的结果为准
177+
thenCalledOrThrow = true
178+
return reject(e)
179+
}
180+
} else {
181+
resolve(x)
103182
}
104183
}
105184

106185
var a = new Promise(resolve => {
107-
resolve(1)
186+
setTimeout(() => {
187+
resolve(1)
188+
}, 500)
108189
})
109190
.then(res => {
110-
console.log(res)
191+
console.log("res1", res)
111192
return new Promise(r => {
112-
setTimeout(() => {
113-
r(15)
114-
}, 1000)
193+
r(
194+
new Promise(r1 => {
195+
r1(15)
196+
}),
197+
)
115198
})
116199
})
117200
.then(res => {
118-
console.log("res", res)
201+
console.log("res2", res)
119202
})

0 commit comments

Comments
 (0)