Promise是一个有状态的构造函数,出自ES6,主要用于实现异步编程,API请求等。它的出现避免了以往的回调地狱的问题,使得代码更加清晰,易于维护。该构造函数主要有以下几部分组成,分别是:构造器,实例方法:then,catch,finally。静态方法:resolve,reject,race,all等。
本文将从以下步骤分别实现上述功能:
1.构造函数
定义类 -> 添加构造函数-> 设置状态及原因->定义resolve/reject-> 设置状态不可逆->执行回调函数
代码如下:
/*
定义3个变量
pending:等待;fulfilled:执行成功;rejected:执行失败
*/
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MYPromise {
// 定义变量保存状态
status = PENDING;
// 定义变量用来存储原因
result = undefined;
// 保存回调函数
#handlers = [];
constructor(func) {
const resolve = (result) => {
// 设置状态不可逆
if (this.status == PENDING) {
this.status = FULFILLED;
this.result = result;
// 调用成功回调
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result);
});
}
};
const reject = (result) => {
// 设置状态不可逆
if (this.status == PENDING) {
this.status = REJECTED;
this.result = result;
// 调用失败回调
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result);
});
}
};
try {
func(resolve, reject);
} catch (error) {
reject(error);
}
}
}
运行的结果如下:Promise的状态变更时不可逆的,只有pending->fulfilled,pending->rejected;
2.实现实例方法then
实现思路:添加实例方法->进行参数判断->执行成功回调->执行失败回调->处理异步和多次调用的问题。
代码如下:
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled == "function" ? onFulfilled : (x) => x;
onRejected =
typeof onRejected == "function"
? onRejected
: (x) => {
throw x;
};
const p2 = new MYPromise((resolve, reject) => {
// 执行成功回调
if (this.status == FULFILLED) {
handlerSyncTask(() => {
try {
const x = onFulfilled(this.result);
resolvePromise(x, p2, resolve, reject);
} catch (err) {
reject(err);
}
});
} else if (this.status == REJECTED) {
handlerSyncTask(() => {
try {
const x = onRejected(this.result);
resolvePromise(x, p2, resolve, reject);
} catch (err) {
reject(err);
}
});
// 异步时,保存回调函数
} else if (this.status == PENDING) {
this.#handlers.push({
onFulfilled: () => {
handlerSyncTask(() => {
try {
const x = onFulfilled(this.result);
resolvePromise(x, p2, resolve, reject);
} catch (error) {
reject(error);
}
});
},
onRejected: () => {
handlerSyncTask(() => {
try {
const x = onRejected(this.result);
resolvePromise(x, p2, resolve, reject);
} catch (error) {
reject(error);
}
});
},
});
}
});
return p2;
}
运行结果如下:
2.1 执行成功的回调
2.2 执行失败的回调
2.3 处理异步的情况
在Promise中,代码的执行书序分别是:主任务 ->微任务 ->宏任务(setTimeout);当new一个Promise时,传入的回调函数为同步代码,会立即执行,而then,catch里面的为异步任务。
以下为封装的异步函数,并在then方法中进行调用:
then方法中异步任务的执行结果如下:
2.4 处理多次调用的情况
运行结果如下:
3 实现链式编程
3.1 封装函数,处理重复引用,返回值是Promise,和普通值的情况(fulfilled)
代码如下:
测试并运行结果如下:
3.11 处理返回值
3.12 返回值是Promise
3.13 处理重复引用的异常
3.2 处理rejected
代码如下:
执行结果如下:
3.3 处理pending 状态
执行结果如下:
4 实例方法catch
catch方法相当于then方法中的第二个回调函数功能。其实现代码如下:
调用catch方法,执行结果如下:
5 实例方法finally
Promise无论执行成功,或是失败,都会执行finally方法。代码如下:
代码执行结果如下:
6 静态方法resolve
resolve可通过构造函数直接调用,代码如下:
执行代码,结果如下:
7 静态方法 reject
执行结果如下:
8 静态方法 race
race方法用于处理多个异步任务的情况,入参是一个可迭代的对象。等待期中某一个任务执行完毕并返回。其代码如下:
测试代码执行结果如下:
9 静态方法 all
all方法也是用于处理多个异步任务的情况,与race不同的是,all方法会等到所有异步任务执行完毕并返回结果,当有一个任务执行异常,会直接返回异常的任务.代码如下:
代码运行结果如下:
附录:
完成代码如下:
// 封装异步函数,在then方法中进行回调
function handlerSyncTask(callback) {
if (typeof queueMicrotask == "function") {
queueMicrotask(callback);
} else if (typeof MutationObserver == "function") {
const obs = new MutationObserver(callback);
const divNode = document.createElement("div");
obs.observe(divNode, { childList: true });
divNode.innerText("synctask");
} else {
setTimeout(callback, 0);
}
}
// 封装方法-判断返回值类型并进行处理
function resolvePromise(x, p2, resolve, reject) {
if (x === p2) {
throw new TypeError("chaining cycle detected for promise");
}
if (x instanceof MYPromise) {
x.then(
(res) => resolve(res),
(err) => reject(err)
);
} else {
resolve(x);
}
}
/*
定义3个变量
pending:等待;fulfilled:执行成功;rejected:执行失败
*/
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MYPromise {
// 定义变量保存状态
status = PENDING;
// 定义变量用来存储原因
result = undefined;
// 保存回调函数
#handlers = [];
constructor(func) {
const resolve = (result) => {
// 设置状态不可逆
if (this.status == PENDING) {
this.status = FULFILLED;
this.result = result;
// 调用成功回调
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result);
});
}
};
const reject = (result) => {
// 设置状态不可逆
if (this.status == PENDING) {
this.status = REJECTED;
this.result = result;
// 调用失败回调
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result);
});
}
};
try {
func(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled == "function" ? onFulfilled : (x) => x;
onRejected =
typeof onRejected == "function"
? onRejected
: (x) => {
throw x;
};
const p2 = new MYPromise((resolve, reject) => {
// 执行成功回调
if (this.status == FULFILLED) {
handlerSyncTask(() => {
try {
const x = onFulfilled(this.result);
resolvePromise(x, p2, resolve, reject);
} catch (err) {
reject(err);
}
});
} else if (this.status == REJECTED) {
handlerSyncTask(() => {
try {
const x = onRejected(this.result);
resolvePromise(x, p2, resolve, reject);
} catch (err) {
reject(err);
}
});
// 异步时,保存回调函数
} else if (this.status == PENDING) {
this.#handlers.push({
onFulfilled: () => {
handlerSyncTask(() => {
try {
const x = onFulfilled(this.result);
resolvePromise(x, p2, resolve, reject);
} catch (error) {
reject(error);
}
});
},
onRejected: () => {
handlerSyncTask(() => {
try {
const x = onRejected(this.result);
resolvePromise(x, p2, resolve, reject);
} catch (error) {
reject(error);
}
});
},
});
}
});
return p2;
}
// catch方法
catch(onrejected) {
return this.then(undefined, onrejected);
}
// finally 方法
finally(onfinally) {
return this.then(onfinally, onfinally);
}
/*
静态方法:resolve
*/
static resolve(value) {
if (value instanceof MYPromise) {
return value;
}
return new MYPromise((resolve, reject) => {
resolve(value);
});
}
/*
静态方法:reject
*/
static reject(value) {
return new MYPromise((undefined, reject) => {
reject(value);
});
}
/*
静态方法:race
*/
static race(promise) {
return new MYPromise((resolve, reject) => {
if (!Array.isArray(promise)) {
return reject(new TypeError("arguments is not iterable"));
}
promise.forEach((p) => {
MYPromise.resolve(p).then(
(res) => resolve(res),
(err) => reject(err)
);
});
});
}
/*
静态方法:all,获取所有的执行结果
*/
static all(promise) {
return new MYPromise((resolve, reject) => {
if (!Array.isArray(promise)) {
return reject(new TypeError("argument is not iterable"));
}
promise.length == 0 && resolve(promise);
let results = [];
let count = 0;
promise.forEach((p, index) => {
MYPromise.resolve(p).then(
(res) => {
results[index] = res;
count++;
count === promise.length && resolve(results);
},
(err) => {
reject(err);
}
);
});
});
}
}