前言:
相信在工作中各位小伙伴都使用过 Promise,但是它是如何实现的呢,今天就由我来给大家分享一下手写 Promise,及其相关拓展方法的实现,希望对大家有所帮助!
代码:
// proise 三种状态
const PENDING = "PENDING";
const FULFILLED = "FULFILLED";
const REJECTED = "REJECTED";
function resolvePromise(promise, x, resolve, reject) {
// x 的值 来决定 走 resolve,还是 reject
// 需要考虑不同 promise 相互兼容,按照 promiseplus 规范实现,保证兼容性
if (promise === x) {
return reject(
new TypeError("TypeError:Chaining cycle detected for promise !")
);
}
// 判断 x 是不是一个 promise ,如果不是 promise 就直接用这个值,将promise 变为成功态
if ((typeof x === "object" && x !== null) || typeof x === "function") {
let called = false;
try {
let then = x.then; // 这个x 可能是通过 definproperty 定义的,或者是三方的 promise,这时候我们取then的时候可能会报错!
if (typeof then === "function") {
// x.then() // 不要这样写,因为 then 的指向可能发生变化,以第一次获取的为准!
// x 是一个 promise 用x 的状态决定成功或者失败
then.call(
x,
(y) => {
if (called) return; // 防止 用户既调用成功,也调用失败,预防三方 promise 没有处理 连续调用 成功 和 失败
called = true;
// resolve(y);
resolvePromise(promise, y, resolve, reject); //递归解析 y 的值
},
(r) => {
if (called) return; // 防止 用户既调用成功,也调用失败,预防三方 promise 没有处理 连续调用 成功 和 失败
called = true;
// 一旦失败,不继续解析
reject(r);
}
);
} else {
// then 为普通值 {then:123}
resolve(x);
}
} catch (err) {
if (called) return; // 防止 用户既调用成功,也调用失败,预防三方 promise 没有处理 连续调用 成功 和 失败
called = true;
reject(err);
}
} else {
// 不是对象和函数,是普通值
resolve(x);
}
}
class Promise {
constructor(executor) {
this.status = PENDING; //promise 默认状态
this.value = undefined; //成功的值
this.reason = undefined; //失败的原因
this.onResolveCallBacks = []; //成功回调队列
this.onRejectCallBacks = []; //失败回调队列
const resolve = (value) => {
// 更改成功状态
if (this.status === PENDING) {
this.value = value;
this.status = FULFILLED;
this.onResolveCallBacks.forEach((cb) => cb(this.value));
}
};
const reject = (reason) => {
// 更改失败状态
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECTED;
this.onRejectCallBacks.forEach((cb) => cb(this.reason));
}
};
try {
executor(resolve, reject); // 执行器方法,立即执行,报错就立刻更改为失败状态
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (v) => v;
onRejected =
typeof onRejected === "function"
? onRejected
: (e) => {
throw e;
};
// then 方法调用的时候会判断 是执行成功回调还是失败回调
// 可以 不停的 then 下去
let p1 = new Promise((resolve, reject) => {
// x 为 普通值,将x 直接传递给 resovle
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(p1, x, resolve, reject);
} catch (err) {
reject(err);
}
});
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(p1, x, resolve, reject);
} catch (err) {
reject(err);
}
});
}
if (this.status === PENDING) {
// 发布订阅模式,解决调用 then的时候 proise 状态还没发生改变,将回调存起来,等待状态发生变化的时候统一调用
this.onResolveCallBacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(p1, x, resolve, reject);
} catch (err) {
reject(err);
}
});
});
this.onRejectCallBacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(p1, x, resolve, reject);
} catch (err) {
reject(err);
}
});
});
}
});
return p1;
}
static resolve(value) {
if (value instanceof Promise) {
return value;
}
return new Promise((resolve, reject) => {
resolve(value);
});
}
static reject(value) {
// if (value instanceof Promise) {
// return value;
// }
return new Promise((resolve, reject) => {
reject(value);
});
}
catch(errCallback) {
return this.then(null, errCallback);
}
static all(promiseList) {
let result = [];
let total = 0;
return new Promise((resolve, reject) => {
function processResult(data, index) {
result[index] = data;
if (++total === promiseList.length) {
resolve(result);
}
}
promiseList.forEach((item, i) => {
Promise.resolve(item).then((data) => {
processResult(data, i);
}, reject);
});
});
}
static race(promiseList) {
return new Promise((resolve, reject) => {
promiseList.forEach((item, i) => {
Promise.resolve(item).then(resolve, reject);
});
});
}
static allSettled(promiseList) {
let result = [];
let total = 0;
return new Promise((resolve, reject) => {
function processResult(data, index, status) {
result[index] = { status, value: data };
if (++total === promiseList.length) {
resolve(result);
}
}
promiseList.forEach((item, i) => {
Promise.resolve(item).then(
(data) => {
processResult(data, i, "fulfilled");
},
(err) => {
processResult(err, i, "rejected");
}
);
});
});
}
// 无论成功失败都会执行
finally(finallyCallback) {
return this.then(
(data) => {
return Promise.resolve(finallyCallback()).then(() => data);
},
(err) => {
return Promise.resolve(finallyCallback()).then(() => {
throw err;
});
}
);
}
}
function promisify(fn) {
return function (...args) {
return new Promise((resolve, reject) => {
fn(...args, function (err, data) {
if (err) return reject(err);
resolve(data);
});
});
};
}
Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
};
module.exports = Promise;
功能测试:
接下来我们需要测试一下上边的代码是否满足 Promise-plus 规范,因此我们使用 官方测试程序进行测试。
npm i promises-aplus-tests // 安装测试程序
// promises-aplus-tests 文件名称
promises-aplus-tests myPromise.js
等待程序跑完所有的用例即可展示如上图效果,证明我们写的 Promise 是基本上没问题的!
如有任何问题,请留言或者私信我,我会及时回复大家的问题!