Promise(二):手动实现一个 Promise
上一篇文章我们认识了 Promise 的基本用法,现在来尝试手动来实现一下简单的 Promise 功能。
简易版 Promise
javascript
/*创建三个变量来表示状态*/
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
function myPromise(fn) {
/* that 保存 this ,避免 this 指向问题*/
const that = this;
/*value 用来保存 resolve 或 reject 中传入的值*/
that.value = null;
/*默认状态*/
that.status = PENDING;
/*
*用于保存 then 中的回调
*当执行完 Promise 时状态可能还是等待中,这时候应该把 then 中的回调保存起来用于状态改变时使用
*/
that.fulfilledCallback = [];
that.rejectedCallback = [];
function resolve(value) {
if (that.status === PENDING) {
/*改变status状态*/
that.status = FULFILLED;
/*保存传入的value值*/
that.value = value;
/*执行回调方法*/
that.fulfilledCallback.forEach((fun) => fun(that.value));
}
}
function reject(value) {
if (that.status === PENDING) {
/*改变status状态*/
that.status = REJECTED;
/*保存传入的value值*/
that.value = value;
/*执行回调方法*/
that.rejectedCallback.forEach((fun) => fun(that.value));
}
}
/*执行回调*/
try {
fn(resolve, reject);
} catch (e) {
reject(e);
}
}
/*
*考虑到所有的实例都要用到then方法,then方法得放在promise的原型链上。
*当状态是PENDING状态时,该做什么?不执行回调,那就将回调方法分别放入不同的栈内,等待调用。
*当状态为FULFILLED或者REJECTED时,则执行响应的方法即可。
*/
myPromise.prototype.then = function (resolveFun, rejectFun) {
let _this = this;
if (_this.status === PENDING) {
/*等待状态,添加回调函数到栈中*/
_this.fulfilledCallback.push(() => {
resolveFun(_this.value);
});
_this.rejectedCallback.push(() => {
rejectFun(_this.value);
});
}
if (_this.status === FULFILLED) {
resolveFun(_this.value);
}
if (_this.status === REJECTED) {
rejectFun(_this.value);
}
};
let pro = new myPromise((resolve, reject) => {
console.log("myPromise");
resolve("data");
});
pro.then((res) => {
console.log(res);
});好了,一个简易的 Promise 就完成了,我们来看一下结果:

优化
resolve 和 reject 的改造
根据 promise+规范改造 promise,传给 then 的应该是个 promise。 resolve 和 reject 的改造:
- 对于 resolve 函数来说,首先需要判断传入的值是否为 Promise 类型
- 为了保证函数执行顺序,需要将两个函数体代码使用 setTimeout 包裹起来
javascript
function resolve(value) {
/*判断value值是否为Promise类型*/
if (value instanceof myPromise) {
return value.then(resolve, reject);
}
/*为保证函数执行顺序,将函数体包裹在setTimeout中*/
setTimeout(() => {
if (that.status === PENDING) {
/*改变status状态*/
that.status = FULFILLED;
/*保存传入的value值*/
that.value = value;
/*执行回调方法*/
that.fulfilledCallback.forEach((fun) => fun(that.value));
}
}, 0);
}
function reject(value) {
/*为保证函数执行顺序,将函数体包裹在setTimeout中*/
setTimeout(() => {
if (that.status === PENDING) {
/*改变status状态*/
that.status = REJECTED;
/*保存传入的value值*/
that.value = value;
/*执行回调方法*/
that.rejectedCallback.forEach((fun) => fun(that.value));
}
}, 0);
}then 方法优化
javascript
myPromise.prototype.then = function (resolveFun, rejectFun) {
let _this = this;
/*新增一个变量 promise2,因为每个 then 函数都需要返回一个新的 Promise 对象,该变量用于保存新的返回对象*/
let promise2 = null;
resolveFun = typeof resolveFun === "function" ? resolveFun : (res) => res;
rejectFun =
typeof rejectFun === "function"
? rejectFun
: (val) => {
throw val;
};
if (_this.status === PENDING) {
/*等待状态,添加回调函数到栈中*/
return (promise2 = new myPromise((resole, reject) => {
_this.fulfilledCallback.push(() => {
try {
let val = resolveFun(_this.value);
resultPromise(promise2, val, resolve, reject);
} catch (e) {
reject(e);
}
});
_this.rejectedCallback.push(() => {
try {
let val = rejectFun(_this.value);
resultPromise(promise2, val, resolve, reject);
} catch (e) {
reject(e);
}
rejectFun(_this.value);
});
}));
}
if (_this.status === FULFILLED) {
return (promise2 = new myPromise((resole, reject) => {
setTimeout(() => {
try {
let val = resolveFun(_this.value);
resultPromise(promise2, val, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}));
}
if (_this.status === REJECTED) {
return (promise2 = new myPromise((resolve, reject) => {
setTimeout(() => {
try {
let val = rejectFun(_this.value);
resultPromise(promise2, val, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}));
}
};如果 val 处于等待状态,Promise 需保持为等待状态直至 val 被执行或拒绝 如果 val 处于其他状态,则用相同的值处理 Promise
javascript
resultPromise(promise, val, resolve, reject){
/*为了防止回调地狱的情况,需要判断一下 promise2 与当前结果的关系
* 如果相等,这说明出现回调地狱,就抛出一个错误
*/
if(promise === val){
return reject(new TypeError('循环引用') )
}
/*判断val类型*/
if (val instanceof myPromise) {
val.then(function (value) {
resultPromise(promise, value, resolve, reject)
}, reject)
}
/*创建一个变量 bool 用于判断是否已经调用过函数*/
let bool = false;
if(val !== null && (typeof val === 'object' || typeof val === 'function') ){
try{
/*因为每个 promsie 都会有一个 then 方法,用变量 then 来保存它;如果出现错误,直接执行 reject 方法*/
let then = val.then;
/*判断then方法的类型,如果是 function;就认为返回的是一个 promise,否则就是一个普通的值,直接调用 resolve 方法*/
if( typeof then === 'function'){
/*让then方法执行,判断执行的结果,如果成功就走 resolve ;失败就走 reject
* 因为当前上下文的 this 指向的并不是 val,所以通过 call 方法改变this指向 val
*/
then.call(val, (data)=>{
if(bool) return;
bool = true;
/*通过递归解析,重复执行,直到返回的结果不是一个 promise 为止*/
resultPromise(promise2, data, resolve, reject)
},(e)=>{
if(e) return;
bool = true;
reject(e)
})
}else {
resolve(val)
}
} catch(e){
if(bool) return;
bool = true;
reject(e)
}
}else {
/*如果当前的值不是一个函数也不是一个对象,那说明是一个普通值,就直接进入下一次的成功方法*/
resolve(val)
}
}完整代码
以上就是修改的内容了,来将代码整理一下:
javascript
/*创建三个变量来表示状态*/
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
function myPromise(fn) {
/* that 保存 this ,避免 this 指向问题*/
const that = this;
/*value 用来保存 resolve 或 reject 中传入的值*/
that.value = null;
/*默认状态*/
that.status = PENDING;
/*
*用于保存 then 中的回调
*当执行完 Promise 时状态可能还是等待中,这时候应该把 then 中的回调保存起来用于状态改变时使用
*/
that.fulfilledCallback = [];
that.rejectedCallback = [];
function resolve(value) {
/*判断value值是否为Promise类型*/
if (value instanceof myPromise) {
return value.then(resolve, reject);
}
/*为保证函数执行顺序,将函数体包裹在setTimeout中*/
setTimeout(() => {
if (that.status === PENDING) {
/*改变status状态*/
that.status = FULFILLED;
/*保存传入的value值*/
that.value = value;
/*执行回调方法*/
that.fulfilledCallback.forEach((fun) => fun(that.value));
}
}, 0);
}
function reject(value) {
/*为保证函数执行顺序,将函数体包裹在setTimeout中*/
setTimeout(() => {
if (that.status === PENDING) {
/*改变status状态*/
that.status = REJECTED;
/*保存传入的value值*/
that.value = value;
/*执行回调方法*/
that.rejectedCallback.forEach((fun) => fun(that.value));
}
}, 0);
}
/*执行回调*/
try {
fn(resolve, reject);
} catch (e) {
reject(e);
}
}
myPromise.prototype.then = function (resolveFun, rejectFun) {
let _this = this;
/*新增一个变量 promise2,因为每个 then 函数都需要返回一个新的 Promise 对象,该变量用于保存新的返回对象*/
let promise2 = null;
resolveFun = typeof resolveFun === "function" ? resolveFun : (res) => res;
rejectFun =
typeof rejectFun === "function"
? rejectFun
: (val) => {
throw val;
};
if (_this.status === PENDING) {
/*等待状态,添加回调函数到栈中*/
return (promise2 = new myPromise((resole, reject) => {
_this.fulfilledCallback.push(() => {
try {
let val = resolveFun(_this.value);
resultPromise(promise2, val, resolve, reject);
} catch (e) {
reject(e);
}
});
_this.rejectedCallback.push(() => {
try {
let val = rejectFun(_this.value);
resultPromise(promise2, val, resolve, reject);
} catch (e) {
reject(e);
}
rejectFun(_this.value);
});
}));
}
if (_this.status === FULFILLED) {
return (promise2 = new myPromise((resole, reject) => {
setTimeout(() => {
try {
let val = resolveFun(_this.value);
resultPromise(promise2, val, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}));
}
if (_this.status === REJECTED) {
return (promise2 = new myPromise((resolve, reject) => {
setTimeout(() => {
try {
let val = rejectFun(_this.value);
resultPromise(promise2, val, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}));
}
};
function resultPromise(promise, val, resolve, reject) {
/*为了防止回调地狱的情况,需要判断一下 promise2 与当前结果的关系
* 如果相等,这说明出现回调地狱,就抛出一个错误
*/
if (promise === val) {
return reject(new TypeError("循环引用"));
}
/*判断val类型*/
if (val instanceof myPromise) {
val.then(function (value) {
resultPromise(promise, value, resolve, reject);
}, reject);
}
/*创建一个变量 bool 用于判断是否已经调用过函数*/
let bool = false;
if (val !== null && (typeof val === "object" || typeof val === "function")) {
try {
/*因为每个 promsie 都会有一个 then 方法,用变量 then 来保存它;如果出现错误,直接执行 reject 方法*/
let then = val.then;
/*判断then方法的类型,如果是 function;就认为返回的是一个 promise,否则就是一个普通的值,直接调用 resolve 方法*/
if (typeof then === "function") {
/*让then方法执行,判断执行的结果,如果成功就走 resolve ;失败就走 reject
* 因为当前上下文的 this 指向的并不是 val,所以通过 call 方法改变this指向 val
*/
then.call(
val,
(data) => {
if (bool) return;
bool = true;
/*通过递归解析,重复执行,直到返回的结果不是一个 promise 为止*/
resultPromise(promise2, data, resolve, reject);
},
(e) => {
if (e) return;
bool = true;
reject(e);
}
);
} else {
resolve(val);
}
} catch (e) {
if (bool) return;
bool = true;
reject(e);
}
} else {
/*如果当前的值不是一个函数也不是一个对象,那说明是一个普通值,就直接进入下一次的成功方法*/
resolve(val);
}
}执行结果
现在来使用一下,看下结果:
javascript
function p1() {
let p1 = new myPromise((resolve, reject) => {
resolve(111);
});
return p1;
}
function p2() {
let p2 = new myPromise((resolve, reject) => {
setTimeout(() => {
resolve(222);
console.log("第二次");
}, 2000);
});
return p2;
}
function p3() {
let p3 = new myPromise((resolve, reject) => {
setTimeout(() => {
resolve(333);
console.log("第三次");
}, 3000);
});
return p3;
}
p1()
.then(
(res) => {
console.log(res);
return p2();
},
(err) => {
console.log("err", err);
}
)
.then((res) => {
console.log(res);
return p3();
})
.then((res) => {
console.log(res);
return "直接返回数据";
})
.then((res) => {
console.log(res);
});打印结果如下:
