深入了解Promise
本文主要讲解 Promise 的常用方法以及使用技巧,并实现如何手写一个 Promise。
Promise 的出现
回调地狱问题
在传统的 JS 编程中始终存在一个问题,即当当前回调函数的执行依赖于上一个回调函数的执行结果的时候,会形成回调函数层层嵌套的问题,严重影响代码的可读性与可维护性,这种现象一般称之为回调地狱。
下面为示例代码,回调地狱的一个比较常见的情景为ajax
请求,即下一个请求的是否发起依赖于上一个请求的结果。
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
let xhr = new XMLHttpRequest();
xhr.open(
"get",
"https://v0.yiketianqi.com/api?unescape=1&version=v61&appid=82294778&appsecret=4PKVFula&city=%E5%8C%97%E4%BA%AC"
);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
console.log(xhr.responseText);
//伪代码....
let xhr = new XMLHttpRequest();
xhr.open("get", "http://www.xx.com?a" + xhr.responseText);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
console.log(xhr.responseText);
}
}
};
}
}
};
Promise 的出现
Promise
是什么?其解决了什么问题?Promise
是异步编程的一种解决方案,比传统的解决方案回调函数更合理、更强大。ES6 将其写进了语言标准,统一了用法,原生提供了Promise
对象。指定回调函数的方式也变得更加灵活易懂,也解决了异步回调地狱的问题旧方案是单纯使用回调函数,常见的异步操作有:定时器、fs 模块、ajax、数据库操作。从语法上说,Promise
是一个构造函数;从功能上说,Promise
对象用来封装一个异步操作并可以获取其成功/失败的结果值。Promise
设计的核心理念是什么?- 从
Promise
的角度来说,是将状态改变与回调函数彻底区分开。 - 从应用
Promise
的角度来说,以ajax
请求数据为例,则是将数据请求与数据处理区分开。
- 从
Promise 的实际应用
案例 1:利用 promise 来进行读取文件操作
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
//1.普通文件读取方式
const fs = require("fs");
//2.直接利用readfile来进行读取
/* fs.readFile(__dirname + '/data.txt',(err,data)=>{
if(err) throw err;
console.log(data.toString());
}) */
//3.利用promise来实现文件的读取
const p = new Promise((resolve, reject) => {
fs.readFile(__dirname + "/data.txt", (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
p.then(
(value) => {
console.log(value.toString());
},
(reason) => {
console.log(reason);
}
);
案例 2:利用 promise 进行 ajax 请求
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
<body>
<button>发送ajax请求</button>
<script>
//1.获取DOM元素对象
let btn = document.querySelector("button");
//2.绑定事件
btn.onclick = function () {
//3.创建promise实例对象
const p = new Promise((resolve, reject) => {
//4.创建ajax实例对象
const xhr = new XMLHttpRequest();
//5.打开请求
xhr.open(
"get",
"https://www.yiketianqi.com/free/day?appid=82294778&appsecret=4PKVFula&unescape=1"
);
//6.发送请求
xhr.send();
//7.利用onreadystatechange事件
xhr.onreadystatechange = function () {
//8.判断
if (xhr.readyState == 4) {
if (xhr.status == 200) {
resolve(xhr.responseText);
} else {
reject(xhr.response);
}
}
};
});
p.then(
(value) => {
console.log(JSON.parse(value));
},
(reason) => {
console.log("获取信息失败");
}
);
};
</script>
</body>
案例 3:利用 promise 进行数据库操作
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
const mongoose = require("mongoose");
new Promise((resolve, reject) => {
mongoose.connect("mongodb://127.0.0.1/project");
mongoose.connection.on("open", () => {
//连接成功的情况
resolve();
});
mongoose.connection.on("error", () => {
//连接失败的情况
reject();
});
}).then(
(value) => {
//创建结构
const NoteSchema = new mongoose.Schema({
title: String,
content: String,
});
//创建模型
const NoteModel = mongoose.model("notes", NoteSchema);
//读取操作
NoteModel.find().then(
(value) => {
console.log(value);
},
(reason) => {
console.log(reason);
}
);
},
(reason) => {
console.log("连接失败");
}
);
案例 4:封装一个函数,作用是读取文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const fs = require("fs");
function ReadFileFun(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, (err, data) => {
//判断
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
ReadFileFun("./data.txt").then(
(value) => {
console.log(value.toString());
},
(reason) => {
console.log(reason);
}
);
node
中的 promisify
promisify
(只能在NodeJS
环境中使用)promisify
是util
模块中的一个方法util
是nodeJS
的内置模块- 作用: 返回一个新的函数, 函数是
promise
风格的.
1
2
3
4
5
6
7
8
9
10
11
12
13
const util = require("util");
const fs = require("fs");
//通过 fs.readFile 创建一个新的函数
const mineReadFile = util.promisify(fs.readFile);
mineReadFile("./resource/2.html").then(
(value) => {
console.log(value.toString());
},
(reason) => {
console.log(reason);
}
);
查看 promisify 的手写实现
看到 promisify 这个函数对其内部实现机制比较感兴趣,那我们就来手写一下。
首先
promisify
函数得返回一个函数,同时返回的这个函数应该返回一个Promise
对象,根据这两点我们把函数的基本结构搭建起来。1
2
3
4
5const promisify = () => { return function () { return new Promise((resolve, reject) => {}); }; };
利用返回的这个
Promise
对象,可以使用then
方法进行回调的处理,即原来函数的回调决定这Promise
状态的改变以及执行,所以需要将改变Promise
对象的状态的回调函数传入参数中。1
2
3
4
5
6
7
8
9
10
11
12
13
14/** * @param {(...args) => void} func * @returns {(...args) => Promise<any} */ const promisify = (func) => { return function (...params) { return new Promise((resolve, reject) => { func.call(this, ...params, (err, data) => { if (err) reject(err); else resolve(data); }); }); }; };
Promise 的实例方法
then
注意点:通过then
返回的promise
的对象的状态由谁决定。
- 若返回非
promise
对象或者什么都不返回则,状态为fullfilled
。 - 若函数执行过程中抛出错误,则状态为
rejected
。 - 若返回一个
promise
对象,则状态与返回的promise
对象保持一致。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const p = new Promise((resolve, reject) => {
resolve("ok");
});
let result = p.then(
(value) => {
throw "错误";
},
(reason) => {
console.log(reason);
}
);
console.log(result);
catch
能够穿透捕获Promise
中的错误,其实相当于Promise.prototype.then(undefined, onRejected)
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
let p = new Promise((resolve, reject) => {
//resolve('success');
reject("error");
});
p.catch((reason) => {
console.log(reason);
});
//then方法中不是必须传入两个参数,可以只传递成功时的回调函数
//也可以单独使用catch来指定失败的回调函数
//异常(错误)穿透
//当如果有多个需要执行的成功时的回调函数,可以不需要每一次都写失败回调,可以统一最后利用catch
//当如果promise对象的状态为reject的话,会一直向下穿透直到catch方法
p.then((value) => {
console.log(value);
})
.then((value) => {
console.log(value);
})
.catch((reason) => {
console.log(reason);
});
finally
finally
是在 ES9(ES2018)中新增的一个特性:表示无论 Promise
对象变成 fufilled
还是 rejected
状态,最终都会被执行。finally
方法中的回调函数是不接受参数的,因为无论前面是 fulfilled
状态还是 rejected
状态, 它都是执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
const p = new Promise((resolve, reject) => {
// resolve('ok');
reject("error");
});
p.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
})
.finally(() => {
console.log("finally");
});
Promise 类静态方法
resolve
- 当参数不是
Promise
对象的时候,返回promise
状态为fullfilled
。 - 当参数是
Promise
对象的时候,返回的Promise
实例的属性由该Promise
实例决定。
1
2
3
4
5
6
7
8
9
let p3 = Promise.resolve(
new Promise((resolve, reject) => {
resolve("success");
})
);
console.log(p3);
let p4 = Promise.resolve(Promise.resolve(Promise.resolve("OK")));
console.log(p4);
reject
始终返回状态为rejected
的Promise
对象
1
2
console.log(Promise.reject(123));
console.log(Promise.reject(Promise.resolve("ok")));
all
接受一个Promise
对象的数组,如果数组中的Promise
对象的状态都是fullfilled
,则返回的也是一个状态为fullfilled
对象,PromiseResult
的值为每个成功值的数组。若存在状态为rejected
的对象则返回一个状态为rejected
的Promise
对象,PromiseResult
为第一个状态为rejected
的Promise
对象。
1
2
3
4
5
6
7
let p1 = new Promise((resolve, reject) => {
resolve("ok");
});
let p2 = Promise.resolve("hello");
let p3 = Promise.resolve("oh yeah");
let result = Promise.all([p1, p2, p3]);
console.log(result);
race
和all
方法类似都是接受一个Promise
对象的数组,但其状态与结果由数组中最先改变的Promise
对象决定。
1
2
3
4
5
6
7
8
9
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("ok");
}, 2000);
});
let p2 = Promise.resolve("success");
let p3 = Promise.resolve("oh hou");
let result = Promise.race([p1, p2, p3]);
console.log(result);
allSettled
与all
方法类似,当数组内所有promise
的状态都确定后执行成功的回调。基本上只有成功的回调。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function ajax(url) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open("get", url, true);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.responseText);
} else {
reject(xhr.responseText);
}
}
};
});
}
any
与all
方法正好相反,只要参数实例有一个变成 fulfilled
状态,包装实例就会变成 fulfiilled
状态;
如果所有参数实例都变成 rejected
,包装实例就会变成 rejected
状态,结果为一个AggregateError
对象。
1
2
3
4
5
6
7
8
9
10
let p1 = new Promise((resolve, reject) =>{" "}
{setTimeout(() => {
resolve("ok");
}, 1000)}
) let p2 = new Promise((resolve, reject) => {setTimeout(() => {
resolve("okk");
}, 2000)}) let p3 = new Promise((resolve, reject) => {setTimeout(() => {
reject("error");
}, 3000)}) Promise.any([p1, p2, p3]).then(res => {console.log(res)}).catch(err
=> {console.log("error")})
关键问题
中断 Promise 链
终止Promise
链条,有且仅有一种方式,即返回一个状态为pending
的promise
对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
new Promise((resolve, reject) => {
resolve(111);
})
.then((value) => {
console.log(value);
console.log(222);
//
// return false;
// throw '出错啦';
//有且只有一种方式 返回一个pending状态的promise对象
return new Promise((resolve, reject) => {});
})
.then((value) => {
console.log(333);
})
.then((value) => {
console.log(444);
})
.catch((reason) => {
console.log(reason);
});
修改 Promise 的状态
1
2
3
4
5
6
7
8
9
10
11
12
13
//如何修改 promise 对象状态
let p = new Promise((resolve, reject) => {
//1. resolve
// resolve('success');
//2. reject
// reject('error');
//3. 抛出错误 异常
// throw '出问题啦! 你说出这样的话 你没有良心!!';
// 状态的改变只有一次
resolve("ok");
reject("error");
});
console.log(p);
Promise 串联多个任务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
new Promise((resolve, reject) => {
console.log(111);
reject();
})
.then((value) => {
console.log(222);
})
.then((value) => {
console.log(value);
})
.then(
(value) => {
console.log(value);
},
(reason) => {
console.error(reason);
}
);
执行顺序分析
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
setTimeout(() => {
console.log("0");
}, 0);
new Promise((resolve, reject) => {
console.log("1");
resolve();
})
.then(() => {
console.log("2");
new Promise((resolve, reject) => {
console.log("3");
resolve();
})
.then(() => {
console.log("4");
})
.then(() => {
console.log("5");
});
})
.then(() => {
console.log("6");
});
new Promise((resolve, reject) => {
console.log("7");
resolve();
}).then(() => {
console.log("8");
});
// 我们来分析一下这段代码执行结果的打印顺序,注意宏队列只会在微队列为空后才会执行
// 1. 同步执行:1 7
// 2. 异步队列中的宏队列与微队列出队列,进入执行栈执行:2 3 8
// 3. 4 比 6 先进微队列,:4 6
// 4. 5 出微队列后为空,宏队列开始执行:5 0
使用 JS 手写一个 promise
由于注释写的比较清除就不分步写了,注意Promise
类的静态方法race
等,接受的是一个可迭代对象,同时注意在写的时候所用到的技巧,foreach
以及数组的原生方法。
值得注意的地方有:
_resolve
的单独处理,处理嵌套的Promise
对象。- 静态方法接受可迭代对象的方法大致相同,但注意空数组的时候返回什么。
- 注意原生实现的时候
then
方法不能使用箭头函数定义,会出现this
指向无法指向实例对象的问题。
原生实现
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
// 首先使用一个自执行函数,避免全局污染
((window) => {
// 注意这里不能使用箭头函数,箭头函数不能用作构造函数
function Promise(executor) {
this.PromiseState = "pending";
this.PromiseResult = undefined;
// 定义储存回调函数的数组
this.callbacks = [];
const _resolve = (value) => {
// 注意 Promise 的状态只能更改一次
if (this.PromiseState !== "pending") return;
// 这里需要对值是 promise 对象进行格外处理
if (value instanceof Promise) {
value.then(_resolve, _reject);
} else {
this.PromiseState = "fullfilled";
this.PromiseResult = value;
this.callbacks.forEach((callback) => {
callback.onResolved();
});
}
};
const _reject = (reason) => {
// 注意 Promise 的状态只能更改一次
if (this.PromiseState !== "pending") return;
this.PromiseState = "rejected";
this.PromiseResult = reason;
this.callbacks.forEach((callback) => {
callback.onRejected();
});
};
try {
executor(_resolve, _reject);
} catch (error) {
_reject(error);
}
}
Object.assign(Promise.prototype, {
// 在这里我们需要明确,then 方法需要返回一个 Promise 对象,并且需要对 onResolved 与 onRejected 是否是一个函数
then(onResolved, onRejected) {
if (!(onResolved instanceof Function)) onResolved = (value) => value;
if (!(onRejected instanceof Function))
onRejected = (reason) => {
throw reason;
};
return new Promise((resolve, reject) => {
// 抽离统一处理的方法
const __common = (callback) => {
// 通过 setTimeout 模拟异步回调的方法
setTimeout(() => {
// 还需要考虑到出错的情况
try {
// 注意我们现在需要通过这个的返回结果获取 then 方法返回的 Promise 的状态
const result = callback(this.PromiseResult);
if (result instanceof Promise) {
// 如果返回的是 Promise 对象,则状态由 Promise 对象决定,则将状态的改变手段,交予该对象的 then 的回调
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
});
};
// 这里 then 方法返回了一个 Promise 对象,其状态应该是由 onResolved 或 onRejected 的执行结果决定的,这里我们首先先判断执行哪一个
if (this.PromiseState === "fullfilled") {
__common(onResolved);
} else if (this.PromiseState === "rejected") {
__common(onRejected);
}
// 同时,这里只考虑到,状态改变后执行回调的情况,没有考虑回调定义在状态改变之前的情况,这里我们来考虑 pending 的情况
else if (this.PromiseState === "pending") {
this.callbacks.push({
onResolved: () => __common(onResolved),
onRejected: () => __common(onRejected),
});
}
});
},
catch(onRejected) {
return this.then(undefined, onRejected);
},
finally(callback) {
// finally 方法是无论如何都会执行并返回一个等效的 Promise 对象
return this.then(
(value) => {
return Promise.resolve(callback()).then(() => value);
},
(reason) => {
return Promise.resolve(callback()).then(() => {
throw reason;
});
}
);
},
});
// 定义类身上的静态方法
// 定义 resolve 方法
Promise.resolve = (value) => {
return new Promise((resolve, reject) => {
if (value instanceof Promise) value.then(resolve, reject);
else resolve(value);
});
};
// 定义 reject 方法
Promise.reject = (reason) => {
return new Promise((resolve, reject) => {
reject(reason);
});
};
// 定义 all 方法
Promise.all = (iterable) => {
if (!iterable[Symbol.iterator]) {
throw new TypeError("Argument must be iterable");
}
return new Promise((resolve, reject) => {
// all 方法则为,当所有状态为 fullfilled 的才会返回成功,有 rejected 就会返回失败
// 将可迭代对象转换为数组
const promises = Array.from(iterable);
// 如果数组为空,直接返回一个已成功的Promise对象,值为一个空数组
if (promises.length === 0) {
return resolve([]);
}
const length = promises.length;
let arr = new Array(length);
let count = 0;
for (let i = 0; i < length; i++) {
if (promises[i] instanceof Promise) {
promises[i].then((value) => {
arr[i] = value;
count++;
if (count === length) resolve(arr);
}, reject);
} else {
arr[i] = promises[i];
count++;
if (count === length) resolve(arr);
}
}
});
};
Promise.race = (iterable) => {
if (!iterable[Symbol.iterator]) {
throw new TypeError("Argument must be iterable");
}
return new Promise((resolve, reject) => {
const promises = Array.from(iterable);
if (promises.length === 0) {
return;
}
for (let i = 0; i < promises.length; i++) {
if (promises[i] instanceof Promise) {
promises[i].then(resolve, reject);
} else {
resolve(promises[i]);
}
}
});
};
// promise.allSettled方法
Promise.allSettled = function (iterable) {
// 参数必须是一个可迭代对象
if (!iterable[Symbol.iterator]) {
throw new TypeError("Argument must be iterable");
}
// 返回一个新的promise对象
return new Promise((resolve, reject) => {
// 将可迭代对象转换为数组
const promises = Array.from(iterable);
// 如果数组为空,直接返回一个已完成的promise,值为一个空数组
if (promises.length === 0) {
resolve([]);
return;
}
// 定义一个结果数组,用来存放每个promise的状态和值或原因
const results = new Array(promises.length);
// 定义一个计数器,用来记录已完成的promise的数量
let count = 0;
// 遍历每个promise
promises.forEach((promise, index) => {
// 将非promise对象转换为promise对象
Promise.resolve(promise)
// 如果成功,将结果对象存入数组,并增加计数器
.then((value) => {
results[index] = { status: "fulfilled", value };
count++;
// 如果所有的promise都完成了,就返回一个已完成的promise,值为结果数组
if (count === promises.length) {
resolve(results);
}
})
// 如果失败,同样将结果对象存入数组,并增加计数器
.catch((reason) => {
results[index] = { status: "rejected", reason };
count++;
// 如果所有的promise都完成了,就返回一个已完成的promise,值为结果数组
if (count === promises.length) {
resolve(results);
}
});
});
});
};
// promise.any方法
Promise.any = function (iterable) {
// 参数必须是一个可迭代对象
if (!iterable[Symbol.iterator]) {
throw new TypeError("Argument must be iterable");
}
// 返回一个新的promise对象
return new Promise((resolve, reject) => {
// 将可迭代对象转换为数组
const promises = Array.from(iterable);
// 如果数组为空,直接返回一个已拒绝的promise,原因为一个空的AggregateError
if (promises.length === 0) {
reject(new AggregateError([]));
return;
}
// 定义一个错误数组,用来存放每个promise的失败原因
const errors = new Array(promises.length);
// 定义一个计数器,用来记录已拒绝的promise的数量
let count = 0;
// 遍历每个promise
promises.forEach((promise, index) => {
// 将非promise对象转换为promise对象
Promise.resolve(promise)
// 如果成功,直接返回一个已完成的promise,值为该promise的值
.then((value) => {
resolve(value);
})
// 如果失败,将失败原因存入错误数组,并增加计数器
.catch((reason) => {
errors[index] = reason;
count++;
// 如果所有的promise都拒绝了,就返回一个已拒绝的promise,原因为一个包含错误数组的AggregateError
if (count === promises.length) {
reject(new AggregateError(errors));
}
});
});
});
};
// 使用自定义的 Promise 替换掉默认的 Promise
window.Promise = Promise;
})(window);
class 实现
原生的都写出来了只能说class
版本有手就行,注意class field
写法的方法仍然属于实例属性,class field
的主要设计目的就是为了解决在类里面使用this
的种种不便,精简了部分代码。
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
class Promise {
constructor(executor) {
this.PromiseState = "pending";
this.PromiseResult = undefined;
this.callbacks = [];
const _resolve = (value) => {
if (this.PromiseState !== "pending") return;
if (value instanceof Promise) value.then(_resolve, _reject);
else {
this.PromiseState = "fullfilled";
this.PromiseResult = value;
this.callbacks.forEach((callback) => callback.onResolved());
}
};
const _reject = (reason) => {
if (this.PromiseState !== "pending") return;
this.PromiseState = "rejected";
this.PromiseResult = reason;
this.callbacks.forEach((callback) => callback.onRejected());
};
try {
executor(_resolve, _reject);
} catch (error) {
_reject(error);
}
}
then(onResolved, onRejected) {
if (!(onResolved instanceof Function)) onResolved = (value) => value;
if (!(onRejected instanceof Function))
onRejected = (reason) => {
throw reason;
};
return new Promise((resolve, reject) => {
const _common = (callback) => {
setTimeout(() => {
try {
const result = callback(this.PromiseResult);
if (result instanceof Promise) result.then(resolve, reject);
else resolve(result);
} catch (error) {
reject(error);
}
});
};
if (this.PromiseState === "fullfilled") {
_common(onResolved);
} else if (this.PromiseState === "rejected") {
_common(onRejected);
} else if (this.PromiseState === "pending") {
this.callbacks.push({
onResolved: () => _common(onResolved),
onRejected: () => _common(onRejected),
});
}
});
}
catch(onRejected) {
return this.then(undefined, onRejected);
}
finally(callback) {
return this.then(
(value) => Promise.resolve(callback()).then(() => value),
(reason) =>
Promise.resolve(callback()).then(() => {
throw reason;
})
);
}
static resolve(value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) value.then(resolve, reject);
else {
resolve(value);
}
});
}
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason);
});
}
static all(iterables) {
if (!iterables[Symbol.iterator]) {
throw new TypeError(
`TypeError: ${typeof iterables} ${iterables} is not iterable (cannot read property Symbol(Symbol.iterator))`
);
}
return new Promise((resolve, reject) => {
const promises = Array.from(iterables);
if (promises.length === 0) return resolve([]);
const results = new Array(promises.length);
let count = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise).then((value) => {
results[index] = value;
count++;
if (count === promises.length) resolve(results);
}, reject);
});
});
}
static race(iterables) {
if (!iterables[Symbol.iterator]) {
throw new TypeError(
`TypeError: ${typeof iterables} ${iterables} is not iterable (cannot read property Symbol(Symbol.iterator))`
);
}
return new Promise((resolve, reject) => {
const promises = Array.from(iterables);
promises.forEach((promise) => {
Promise.resolve(promise).then(resolve, reject);
});
});
}
static allSettled(iterables) {
if (!iterables[Symbol.iterator]) {
throw new TypeError(
`TypeError: ${typeof iterables} ${iterables} is not iterable (cannot read property Symbol(Symbol.iterator))`
);
}
return new Promise((resolve, reject) => {
const promises = Array.from(iterables);
if (promises.length === 0) return resolve([]);
const results = new Array(promises.length);
let count = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise).then(
(value) => {
results[index] = { status: "fullfilled", value };
count++;
if (count === promises.length) resolve(results);
},
(reason) => {
results[index] = { status: "rejected", reason };
count++;
if (count === promises.length) resolve(results);
}
);
});
});
}
static any(iterables) {
if (!iterables[Symbol.iterator]) {
throw new TypeError(
`TypeError: ${typeof iterables} ${iterables} is not iterable (cannot read property Symbol(Symbol.iterator))`
);
}
return new Promise((resolve, reject) => {
const promises = Array.from(iterables);
if (promises.length === 0) return reject(new AggregateError([]));
const results = new Array(promises.length);
let count = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise).then(resolve, (reason) => {
results[index] = reason;
count++;
if (count === promises.length) reject(new AggregateError(results));
});
});
});
}
}