-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathpromise.html
More file actions
178 lines (154 loc) · 5.93 KB
/
Copy pathpromise.html
File metadata and controls
178 lines (154 loc) · 5.93 KB
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script>
let LAST_ERROR = null;
let IS_ERROR = {};
let STATES = {
PENDING: 0,
RESOLVED: 1,
REJECTED: 2
};
function noop() {
}
function tryCallOne(fn, one) {
try {
return fn(one);
} catch (e) {
LAST_ERROR = e;
return IS_ERROR;
}
}
function tryCallTwo(fn, one, two) {
try {
return fn(one, two);
} catch (e) {
LAST_ERROR = e;
return IS_ERROR;
}
}
function Promise(asyncTask) {
this._state = STATES.PENDING;
this._data = null;
this._reason = null;
this._deferreds = [];//then方法返回的promise都会以deferred对象的形式存储在此数组中
if (!asyncTask) asyncTask = noop;
makePromise(asyncTask, this);
}
function makePromise(asyncTask, promise) {
let executed = false;
let ret = tryCallTwo(
asyncTask,
function (data) {
if (executed) return;
executed = true;
resolvePromise(promise, data);
}, function (reason) {
if (executed) return;
executed = true;
rejectPromise(promise, data);
}
);
if (ret === IS_ERROR && !executed) {
// ret === IS_ERROR也有可能是asyncTask内部调用了resolve之后的代码有错导致的,所以要加一个!excecuted判断
executed = true;
rejectPromise(promise, data);
}
}
function resolvePromise(promise, data) {
if (promise === data) {
return rejectPromise(promise, new Error('promise cannot be resolved by itself'));
}
let isFunction = typeof data === 'function';
let isObject = typeof data === 'object';
let thenable = isObject && (typeof data.then) === 'function';
if (thenable) {
// 创建一个新的Promise实例,并且把当前promise的状态关联到该实例
new Promise(data.then.bind(data)).then(
data => resolvePromise(promise, data),
reason => rejectPromise(promise, reason)
);
} else if (isObject && data instanceof Promise) {
// 如果asyncTask用一个其它的promise实例来resolve,则data就是那个resolve的参数
// 利用它添加回调,来关联当前的promise实例
data.then(
data => resolvePromise(promise, data),
reason => rejectPromise(promise, reason)
);
} else {
promise._state = STATES.RESOLVED;
promise._data = data;
finishPromise(promise);
}
}
function rejectPromise(promise, reason) {
promise._state = STATES.REJECTED;
promise._reason = reason;
finishPromise(promise);
}
function finishPromise(promise) {
for (let deferred of promise._deferreds) {
handlerDeferred(promise, deferred);
}
promise._deferreds = [];//必须清空,否则在对已经resolved的实例继续添加回调,会导致以前的回调再次被调用
}
function handlerDeferred(promise, deferred) {
setTimeout(function () {
let onFulfilled = typeof deferred.onFulfilled === 'function' ? deferred.onFulfilled : noop;
let onRejected = typeof deferred.onRejected === 'function' ? deferred.onRejected : noop;
let cb = promise._state === STATES.RESOLVED ? onFulfilled : onRejected;
let ret = tryCallOne(cb, promise._data);
if (ret === IS_ERROR) {
rejectPromise(deferred.promise, LAST_ERROR);
} else if (typeof ret === 'object' && ret instanceof Promise) {
ret.then(
data => resolvePromise(deferred.promise, data),
reason => rejectPromise(deferred.promise, reason)
);
} else {
promise._state === STATES.RESOLVED ? resolvePromise(deferred.promise, promise._data)
: rejectPromise(deferred.promise, promise._reason);
}
});
}
Promise.prototype.then = function (onFulfilled, onRejected) {
let p = new Promise();
this._deferreds.push(new Deferred(p, onFulfilled, onRejected));
if (this._state !== STATES.PENDING) {
finishPromise(this);
}
return p;
};
Promise.prototype.catch = function (onRejected) {
return this.then(null, onRejected);
}
function Deferred(promise, onFulfilled, onRejected) {
this.promise = promise;
this.onFulfilled = onFulfilled;
this.onRejected = onRejected;
}
</script>
<script>
let p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log(111);
resolve({
then: (resolve, reject) => {
setTimeout(() => {
resolve(2222);
}, 5000);
}
})
}, 5000);
}).then(data => {
console.log(data);
})
</script>
</head>
<body>
</body>
</html>