手写 Promise
最近在看 Geeker-Admin 和 naive-ui-pro 这两个前端项目,在封装 Axios 时遇到了一个 Promise 的使用觉得很迷惑。
找了尚硅谷的 Promise 教程视频,视频中有演示如何手写一个 Promise。遂记录下来。
方法介绍
| 方法 | 作用 | 返回结果 |
|---|---|---|
| then() | 处理成功/失败结果 | 新 Promise |
| catch() | 处理失败情况 | 新 Promise |
| resolve() | 创建成功 Promise | 成功状态的 Promise |
| reject() | 创建失败 Promise | 失败状态的 Promise |
| all() | 并行执行,全成功 | 结果数组或第一个失败原因 |
| race() | 竞争执行 | 最先完成的结果 |
then 方法实现
同步代码状态下
如在使用 resolve、reject 方法亦或者执行异常时,then 方法中的回调函数会被调用。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>手写Promise</title>
<!-- <script src="./index.js"></script> -->
</head>
<body>
<script>
const promise = new Promise((resolve, reject) => {
// resolve("success");
// reject("error");
throw "err";
});
promise.then(
(res) => console.log(res),
(reason) => console.warn(reason)
);
</script>
</body>
</html>实现 then 方法的基础版本,处理同步代码状态下的 Promise。
js
function Promise(exector) {
this.PromiseState = "pending";
this.PromiseResult = undefined;
// 保存实例对象的this
const self = this;
function resolve(value) {
if (self.PromiseState !== "pending") return;
self.PromiseState = "fulfilled";
self.PromiseResult = value;
}
function reject(reason) {
if (self.PromiseState !== "pending") return;
self.PromiseState = "rejected";
self.PromiseResult = reason;
}
try {
exector(resolve, reject);
} catch (err) {
reject(err);
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
if (this.PromiseState === "fulfilled") {
onFulfilled(this.PromiseResult);
}
if (this.PromiseState === "rejected") {
onRejected(this.PromiseResult);
}
};异步代码状态下
当使用异步任务调用 resolve 或 reject 方法时,then 方法中的回调函数就不会被调用。
js
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("success");
}, 1000);
});这时就需要将 then 中添加的回调方法保存起来,等到 Promise 状态更改后再执行相应的回调函数。
js
function Promise(exector) {
this.PromiseState = "pending";
this.PromiseResult = undefined;
this.callback = {};
// 保存实例对象的this
const self = this;
function resolve(value) {
if (self.PromiseState !== "pending") return;
self.PromiseState = "fulfilled";
self.PromiseResult = value;
if (self.callback.onFulfilled) {
self.callback.onFulfilled(self.PromiseResult);
}
}
function reject(reason) {
if (self.PromiseState !== "pending") return;
self.PromiseState = "rejected";
self.PromiseResult = reason;
if (self.callback.onRejected) {
self.callback.onRejected(self.PromiseResult);
}
}
try {
exector(resolve, reject);
} catch (err) {
reject(err);
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
if (this.PromiseState === "fulfilled") {
onFulfilled(this.PromiseResult);
}
if (this.PromiseState === "rejected") {
onRejected(this.PromiseResult);
}
if (this.PromiseState === "pending") {
this.callback = {
onFulfilled,
onRejected,
};
}
};支持多个 then 方法
实现多个 then 方法的调用,每个 then 方法都可以添加成功/失败的回调函数。
js
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("success");
// reject("error");
}, 1000);
});
promise.then(
(res) => console.log(res),
(reason) => console.warn(reason)
);
promise.then(
(res) => alert(res),
(reason) => alert(reason)
);按照当前的 Promise 实现,只会执行最后一个添加的 then 回调函数。改造添加回调函数的处理逻辑,将回调函数存储在数组中,在状态更改后按顺序执行。
js
function Promise(exector) {
this.PromiseState = "pending";
this.PromiseResult = undefined;
this.callback = [];
// 保存实例对象的this
const self = this;
function resolve(value) {
if (self.PromiseState !== "pending") return;
self.PromiseState = "fulfilled";
self.PromiseResult = value;
self.callback.forEach((item) => {
item.onFulfilled(self.PromiseResult);
});
}
function reject(reason) {
if (self.PromiseState !== "pending") return;
self.PromiseState = "rejected";
self.PromiseResult = reason;
self.callback.forEach((item) => {
item.onRejected(self.PromiseResult);
});
}
try {
exector(resolve, reject);
} catch (err) {
reject(err);
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
if (this.PromiseState === "fulfilled") {
onFulfilled(this.PromiseResult);
}
if (this.PromiseState === "rejected") {
onRejected(this.PromiseResult);
}
if (this.PromiseState === "pending") {
this.callback.push({
onFulfilled,
onRejected,
});
}
};获取 then 方法的返回
改造 then 方法,使其返回一个 Promise 对象。
同步代码状态下
js
Promise.prototype.then = function (onFulfilled, onRejected) {
return new Promise((resolve, reject) => {
if (this.PromiseState === "fulfilled") {
try {
const result = onFulfilled(this.PromiseResult);
if (result instanceof Promise) {
result.then(
(v) => resolve(v),
(r) => reject(r)
);
} else {
resolve(result);
}
} catch (err) {
reject(err);
}
}
if (this.PromiseState === "rejected") {
onRejected(this.PromiseResult);
}
if (this.PromiseState === "pending") {
this.callback.push({
onFulfilled,
onRejected,
});
}
});
};异步代码状态下
js
Promise.prototype.then = function (onFulfilled, onRejected) {
const self = this;
return new Promise((resolve, reject) => {
if (this.PromiseState === "fulfilled") {
try {
const result = onFulfilled(this.PromiseResult);
if (result instanceof Promise) {
result.then(
(v) => resolve(v),
(r) => reject(r)
);
} else {
resolve(result);
}
} catch (err) {
reject(err);
}
}
if (this.PromiseState === "rejected") {
onRejected(this.PromiseResult);
}
if (this.PromiseState === "pending") {
this.callback.push({
onFulfilled: function () {
try {
const result = onFulfilled(self.PromiseResult);
if (result instanceof Promise) {
result.then(
(v) => resolve(v),
(r) => reject(r)
);
} else {
resolve(result);
}
} catch (err) {
reject(err);
}
},
onRejected: function () {
try {
const result = onRejected(self.PromiseResult);
if (result instanceof Promise) {
result.then(
(v) => resolve(v),
(r) => reject(r)
);
} else {
resolve(result);
}
} catch (err) {
reject(err);
}
},
});
}
});
};方法优化
js
Promise.prototype.then = function (onFulfilled, onRejected) {
const self = this;
return new Promise((resolve, reject) => {
function callback(fn) {
try {
const result = fn(self.PromiseResult);
if (result instanceof Promise) {
result.then(
(v) => resolve(v),
(r) => reject(r)
);
} else {
resolve(result);
}
} catch (err) {
reject(err);
}
}
if (this.PromiseState === "fulfilled") {
callback(onFulfilled);
}
if (this.PromiseState === "rejected") {
callback(onRejected);
}
if (this.PromiseState === "pending") {
this.callback.push({
onFulfilled: function () {
callback(onFulfilled);
},
onRejected: function () {
callback(onRejected);
},
});
}
});
};catch&值传递&异常穿透
实现效果:
js
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("success");
// reject("error");
}, 1000);
});
promise
.then()
.then(() => console.log(111))
.then(() => {
throw "err";
})
.then(() => console.log(333))
.catch((reason) => console.warn(reason));
console.log(promise);实现细节:
js
Promise.prototype.then = function (onFulfilled, onRejected) {
const self = this;
if (typeof onFulfilled !== "function") {
onFulfilled = function (value) {
return value;
};
}
if (typeof onRejected !== "function") {
onRejected = function (reason) {
throw reason;
};
}
return new Promise((resolve, reject) => {
function callback(fn) {
try {
const result = fn(self.PromiseResult);
if (result instanceof Promise) {
result.then(
(v) => resolve(v),
(r) => reject(r)
);
} else {
resolve(result);
}
} catch (err) {
reject(err);
}
}
if (this.PromiseState === "fulfilled") {
callback(onFulfilled);
}
if (this.PromiseState === "rejected") {
callback(onRejected);
}
if (this.PromiseState === "pending") {
this.callback.push({
onFulfilled: function () {
callback(onFulfilled);
},
onRejected: function () {
callback(onRejected);
},
});
}
});
};
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected);
};resolve & reject 实现
js
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(
(v) => resolve(v),
(r) => reject(r)
);
} else {
resolve(value);
}
});
};
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason);
});
};all & race 实现
js
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
let count = 0;
let result = [];
promises.forEach((item, index) => {
item.then(
(v) => {
count++;
result[index] = v;
if (count === promises.length) {
resolve(result);
}
},
(r) => reject(r)
);
});
});
};
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
promises.forEach((item) => {
item.then(
(v) => resolve(v),
(r) => reject(r)
);
});
});
};then 方法异步执行
在使用 Promise 时,then 方法是异步执行的,如下面示例打印结果为:111 333 222
js
const p1 = new Promise((resolve, reject) => {
resolve("success");
console.log(111);
});
p1.then(() => console.log(222));
console.log(333);改造 Promise 代码,在合适地方添加 setTimeout 模拟异步
js
function Promise(exector) {
this.PromiseState = "pending";
this.PromiseResult = undefined;
this.callback = [];
// 保存实例对象的this
const self = this;
function resolve(value) {
if (self.PromiseState !== "pending") return;
self.PromiseState = "fulfilled";
self.PromiseResult = value;
setTimeout(() => {
self.callback.forEach((item) => {
item.onFulfilled(self.PromiseResult);
});
}, 0);
}
function reject(reason) {
if (self.PromiseState !== "pending") return;
self.PromiseState = "rejected";
self.PromiseResult = reason;
setTimeout(() => {
self.callback.forEach((item) => {
item.onRejected(self.PromiseResult);
});
}, 0);
}
try {
exector(resolve, reject);
} catch (err) {
reject(err);
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
const self = this;
if (typeof onFulfilled !== "function") {
onFulfilled = function (value) {
return value;
};
}
if (typeof onRejected !== "function") {
onRejected = function (reason) {
throw reason;
};
}
return new Promise((resolve, reject) => {
function callback(fn) {
try {
const result = fn(self.PromiseResult);
if (result instanceof Promise) {
result.then(
(v) => resolve(v),
(r) => reject(r)
);
} else {
resolve(result);
}
} catch (err) {
reject(err);
}
}
if (this.PromiseState === "fulfilled") {
setTimeout(() => {
callback(onFulfilled);
}, 0);
}
if (this.PromiseState === "rejected") {
setTimeout(() => {
callback(onRejected);
}, 0);
}
if (this.PromiseState === "pending") {
this.callback.push({
onFulfilled: function () {
callback(onFulfilled);
},
onRejected: function () {
callback(onRejected);
},
});
}
});
};整理封装成 Class
js
class Promise {
constructor(exector) {
this.PromiseStatus = "pending";
this.PromiseResult = undefined;
this.callbacks = [];
// 保存实例对象 this 的值
const self = this;
function resolve(value) {
// 这里的 this 是 windows
// console.log(this)
if (self.PromiseStatus !== "pending") {
return;
}
self.PromiseStatus = "fulfilled";
self.PromiseResult = value;
setTimeout(() => {
self.callbacks.forEach((item) => {
item.onFulfilled(value);
});
}, 0);
}
function reject(reason) {
if (self.PromiseStatus !== "pending") {
return;
}
self.PromiseStatus = "rejected";
self.PromiseResult = reason;
setTimeout(() => {
self.callbacks.forEach((item) => {
item.onRejected(reason);
});
}, 0);
}
try {
exector(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
const self = this;
if (typeof onFulfilled !== "function") {
onFulfilled = (value) => value;
}
if (typeof onRejected !== "function") {
onRejected = (reason) => {
throw reason;
};
}
return new Promise((resolve, reject) => {
function callback(type) {
try {
const result = type(self.PromiseResult);
if (result instanceof Promise) {
result.then(
(v) => resolve(v),
(r) => reject(r)
);
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
}
if (this.PromiseStatus === "fulfilled") {
setTimeout(() => {
callback(onFulfilled);
}, 0);
}
if (this.PromiseStatus === "rejected") {
setTimeout(() => {
callback(onRejected);
}, 0);
}
if (this.PromiseStatus === "pending") {
this.callbacks.push({
onFulfilled: function () {
callback(onFulfilled);
},
onRejected: function () {
callback(onRejected);
},
});
}
});
}
catch(onRejected) {
return this.then(undefined, onRejected);
}
static resolve(value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(
(v) => resolve(v),
(r) => reject(r)
);
} else {
resolve(value);
}
});
}
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason);
});
}
static all(promises) {
return new Promise((resolve, reject) => {
const results = [];
let count = 0;
promises.forEach((item, index) => {
Promise.resolve(item).then(
(v) => {
results[index] = v;
count++;
if (count === promises.length) {
resolve(results);
}
},
(r) => {
reject(r);
}
);
});
});
}
static race(promises) {
return new Promise((resolve, reject) => {
promises.forEach((item) => {
item.then(
(v) => {
resolve(v);
},
(r) => {
reject(r);
}
);
});
});
}
}