-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPromisesaplus.js
More file actions
177 lines (168 loc) · 4.6 KB
/
Promisesaplus.js
File metadata and controls
177 lines (168 loc) · 4.6 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
const PENDING = "PENDING";
const FULFILLED = "FULFILLED";
const REJECTED = "REJECTED";
const resolvePromise = (promise2, x, resolve, reject) => {
// console.log(promise2, x);
if (promise2 === x) {
return reject(
new TypeError("Chaining cycle detected for promise #<Promise>")
);
}
if ((typeof x === "object" && x !== null) || typeof x === "function") {
let called;
try {
let then = x.then;
// 说明x是一个promise
if (typeof then === "function") {
then.call(
x,
(y) => {
// y可能还是promise, 递归处理,直到y是一个普通值
if (!called) resolvePromise(promise2, y, resolve, reject);
called = true;
},
(r) => {
if (!called) reject(r);
called = true;
}
);
} else {
//x是一个有then属性的普通对象
resolve(x);
}
} catch (error) {
if (!called) reject(error);
called = true;
}
} else {
// x 是普通值
resolve(x);
}
};
class MYPromise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
this.onfulfilledCallbacks = [];
this.onrejectedCallbacks = [];
const resolve = (value) => {
//状态一旦改变就不能成为别的状态
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
if (this.onfulfilledCallbacks.length)
this.onfulfilledCallbacks.forEach((fn) => fn());
}
};
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
if (this.onrejectedCallbacks.length)
this.onrejectedCallbacks.forEach((fn) => fn());
}
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
//then方法返回一个新的promise,resolve或者reject函数中,返回普通值将会被链式的promise捕获,抛出错误会被catch,返回新的promise将会使用该promise的状态。
then(onfulfilled, onrejected) {
//onfulfilled 和 onrejected是可选参数
onfulfilled =
typeof onfulfilled === "function" ? onfulfilled : (val) => val;
onrejected =
typeof onrejected === "function"
? onrejected
: (err) => {
throw err;
};
let promise2 = new MYPromise((resolve, reject) => {
if (this.status === FULFILLED) {
//使用定时器的原因是异步执行该段代码,以便拿到promise2
setTimeout(() => {
try {
let x = onfulfilled(this.value);
// x可能是普通值,也可能是promise
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onrejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
// 应对 setTimeout的类似于发布订阅模式
if (this.status === PENDING) {
this.onfulfilledCallbacks.push(() => {
// todo
setTimeout(() => {
try {
let x = onfulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
this.onrejectedCallbacks.push(() => {
// todo
setTimeout(() => {
try {
let x = onrejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
return promise2;
}
}
// const p = new Promise((resolve, reject) => {
// // throw new Error("错误");
// // reject(100);
// resolve("成功");
// });
// let p2 = p.then(
// (res) => {
// // console.log(res);
// // return 1000;
// // throw new Error("错误");
// return new Promise((resolve, reject) => {
// resolve("哈哈哈");
// });
// },
// (err) => {
// console.log(err);
// }
// );
// p2.then(
// (res) => {
// console.log(res);
// },
// (err) => {
// console.log(err);
// }
// );
// MYPromise.defer = MYPromise.deferred = function () {
// let dfd = {};
// dfd.promise = new MYPromise((resolve, reject) => {
// dfd.resolve = resolve;
// dfd.reject = reject;
// });
// return dfd;
// };