-
Notifications
You must be signed in to change notification settings - Fork 427
/
Copy pathindex.js
205 lines (183 loc) · 6.36 KB
/
index.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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// promise 的状态值
const PENDING = 'PENDING',
FULFILLED = 'FULFILLED',
REJECTED = 'REJECTED';
/*
* 基础版Promise,提供最基础的功能...
*/
class BasePromise {
constructor( executor ) {
this.status = PENDING; // 默认状态为PENDING
this.value = undefined; // 保存成功状态的值,默认为undefined
this.reason = undefined; // 保存失败状态的值
this.onResolvedCallbacks = []; // 保存成功的回调
this.onRejectedCallbacks = []; // 保存失败的回调
// 成功时调用的方法
const resolve = ( value ) => {
// 状态为PENDING时才可以更新状态,防止executor中调用两次resolve/reject方法
if ( this.status === PENDING ) {
this.status = FULFILLED;
this.value = value;
// 依次执行对应的函数
this.onResolvedCallbacks.forEach(fn => fn());
}
}
// 失败时调用的方法
const reject = ( reason ) => {
// 状态为PENDING时才可以更新状态,防止executor中调用两次resolve/reject方法
if ( this.status === PENDING ) {
this.status = REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try {
// 立即执行, 将resolve和reject函数传给使用者
executor( resolve, reject);
}
catch ( error ) {
// 发生异常是执行逻辑
reject( error )
}
}
// 包含一个then方法,并接收两个参数onFulfilled, onRejected
then( onFulfilled, onRejected ) {
if ( this.status === FULFILLED ) {
onFulfilled(this.value);
}
else if ( this.status === REJECTED ){
onRejected(this.reason);
}
else if ( this.status === PENDING ) {
// 如果promise的状态是PENDING,需要将onFulfilled和onRejected函数存放起来,等待状态确定后,再依次执行对应的函数
this.onResolvedCallbacks.push(() => { onFulfilled(this.value); });
this.onRejectedCallbacks.push(() => { onRejected(this.reason); });
}
}
}
/*
* 完整版Promise
* 提供链式调用与值穿透特性: 链式调用,我们使用Promise时候,当then函数中return一个值时,不管是什么值,我们都能在下一个
* then中获取到,这就是then的链式调用; 值穿透特性,当我们不在then中放入参数,如: promise.then().then(),那么后面的then
* 依旧可以得到之前then返回的值,这就是所谓的值的穿透。
* 实现原理: 如果每次调用then的时候,我们都重新创建一个promise对象,并把上一个then的返回结果传给这个新的promise的then方
* 法,这样就可以一直then下去。
*/
function resolvePromise( promise2, x, resolve, reject ) {
// 如果自己等待自己完成则是错误的实现,用一个类型错误,结束掉promise
if ( promise2 === x ) {
return reject( new TypeError('Chaining cycle detected for promise #<Promise>') );
}
let called; // 是否已调用,只调用一次
if ( (typeof x === 'object' && x !== null) || typeof x === 'function' ) {
try {
// 为了判断resolve过就不再reject了(如reject与resolve同时调用的时候)
let then = x.then;
if ( typeof then === 'function') {
// 不要写成x.then,直接then.call就可以了, 因为x.then会再次取值。
then.call(x, y => {
// 如果执行过,则不再执行
if ( called ) { return; }
called = true;
// 递归解析(因为可能promise中还有promise)
resolvePromise(promise2, y, resolve, reject);
}, r => {
// 只要失败就reject
if ( called ) { return; }
called = true;
reject(r)
})
}
else {
// 如果x.then是一个普通值就直接返回resolve作为结果
resolve(x);
}
}
catch ( error ) {
if ( called ) { return; }
called = true;
reject( error );
}
}
else {
// 如果x.then是一个普通值就直接返回resolve作为结果
resolve(x);
}
}
/*
* Promise完整版类
*/
class FullPromise extends BasePromise {
constructor( executor ) {
super( executor )
}
// 重写基类的方法
then( onFulfilled, onRejected ) {
// 解决onFulfilled, onRejected没有传值的问题
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
// 因为错误的值要让后面访问到,所以这里也要跑出个错误,不然会在之后then的resolve中捕获
onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error; };
// 每次调用then都返回一个新的promise
const promise2 = new FullPromise((resolve, reject) => {
if ( this.status === FULFILLED ) {
setTimeout(() => {
try {
const x = onFulfilled( this.value );
// x可能是一个promise
console.log('fulfilled', promise2);
resolvePromise(promise2, x, resolve, reject);
}
catch ( error ) {
reject( error );
}
}, 0)
}
if ( this.status === REJECTED ) {
setTimeout(() => {
try {
const x = onRejected( this.reason );
resolvePromise(promise2, x, resolve, reject);
}
catch ( error ) {
reject( error )
}
}, 0)
}
if ( this.status === PENDING ) {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled( this.value );
resolvePromise( promise2, x, resolve, reject );
}
catch ( error ) {
reject( error );
}
})
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected( this.reason );
resolvePromise( promise2, x, resolve, reject );
}
catch ( error ) {
reject( error );
}
})
});
}
})
return promise2;
}
}
FullPromise.deferred = function () {
var result = {};
result.promise = new FullPromise(function (resolve, reject) {
result.resolve = resolve;
result.reject = reject;
});
return result;
}
// module.exports = FullPromise;
module.exports = { BasePromise, FullPromise }