实现es6的promise
今天学习一下别人实现的 promise 的代码。
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
let id = 0;
/*
*value状态为执行成功事件的入参,deferreds保存着状态改变之后的需要处理的函数以及promise子节点,构造函
*数里面应该包含这三个属性的初始化
*/
class Promise {
constructor(callback) {
this.id = id;
this.status = PENDING;
this.value = null;
this.defferd = [];
this.resolve = this.resolve.bind(this);
this.reject = this.reject.bind(this);
callback(this.resolve, this.reject);
id++;
}
//触发改变promise状态到FULFILLED
resolve(result) {
console.log(`id: ${this.id} resolve`);
this.status = FULFILLED;
this.value = result;
this.done();
}
//触发改变promise状态到REJECTED
reject(error) {
this.status = REJECTED;
this.value = error;
this.done();
}
// 触发promise defferd里面需要执行的函数
// 只有在resolve和reject的时候才会执行
done() {
if (this.status === PENDING) return;
var defferd = this.defferd;
// if (this.isAsync && this.prevPromise) {
// this.prevPromise.defferd = [];
// this.prevPromise.resolve();
// }
// 如果有defferd,就说明当前是异步操作,异步操作执行resolve的时候,此时defferd中已经包括了下一个then函数
// 如果没有,就说明当前是同步操作,不需要再次执行then函数了。
for (var i = 0; i < defferd.length; i++) {
this.handle(defferd[i]);
}
}
/* 处理defferd
* 如果是同步操作的时候,则直接执行then函数中传递的success或者fail
* 如果是异步操作,那么会等异步操作执行完,再去执行then函数中传递的success或者fail
* 同时这里也会判断success和fail是否还是异步操作
* --------------
* 这里的thenObj指的是
* {
* onfulfiled: 传递给当前promise.then的success函数,
* onrejected: 传递给当前promise.then的fail函数,
* promise: 当前promise重新生成的promise
* defferd: 当前promise需要执行的defferd
* }
*/
handle(thenObj) {
if (!thenObj) {
return;
}
var value = this.value;
var status = this.status;
var p;
if (status === FULFILLED && typeof thenObj.onfulfiled == 'function') {
p = thenObj.onfulfiled(value);
}
if (status === REJECTED && typeof thenObj.onrejected == 'function') {
p = thenObj.onrejected(value);
}
/* new
*如果then中是一个新的Promise对象,则将then函数的defferd函数传给新的promise对象
*这里一定要搞清楚this,thenObj等对象的关系
*这里的this指向的是实例,如果then中是新的Promise对象,则指向改对象
*如果then中不是新的Promise对象,则this指向上个then的作用域,并立即执行resolve()函数
*/
/** new
* 执行defferd函数
* 如果执行的success或fail函数还是返回了promise,就说明这个执行的函数是异步的,需要等待其完成后再执行defferd
* 所以这个时候需要将下个then函数的defferd传递给当前返回的promise,好让他在异步操作完成后继续执行下一个then函数
*
* 如果不是promise,那么直接resolve(),修改status,并执行后面的then
*/
if (p && p.constructor === Promise) {
console.log(`handle promise id:${p.id}`);
p.defferd = thenObj.promise.defferd;
p.isAsync = true;
p.prevPromise = thenObj.promise;
} else {
thenObj.promise.resolve();
}
}
/* 执行then函数
* 储存then函数里面的事件success和fail
* 根据status判断上一个函数是否异步
* 如果是同步,则直接执行handle(等于直接直接执行success和fail函数)
* 如果是异步,则将当前的thenObj存入到上一个函数的defferd中
* ----
* 最后返回一个新的promise对象,可以继续执行下一个then函数
* 并且可以将下一个then函数中的defferd添加到thenObj.promise.defferd中
*
*/
then(success, fail) {
var thenObj = {
onfulfiled: success,
onrejected: fail,
};
var status = this.status;
// key!!!
// 这里是关键,默认生成一个不会resolve的promise
thenObj.promise = new Promise(function () {});
console.log('promise id: ' + thenObj.promise.id);
// 如果还在PENDING,就说明这个时候是异步,需要讲thenObj添加进当前promise的defferd,等异步操作完成再执行defferd
if (status === PENDING) {
this.defferd.push(thenObj);
} else if (status === FULFILLED || status === REJECTED) {
// 如果直接FULFILLED或者REJECTED,就说明在执行then函数的时候已经完成函数执行, 那么直接处理thenObj即可。
this.handle(thenObj);
}
/*
* 这里返回thenObj.promise对象,所以下一个then中的this就指向thenObj.promise
*/
return thenObj.promise;
}
}
let promise1 = new Promise((resolve, reject) => {
resolve(99);
})
.then((res) => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(res + 1), 1000);
});
})
.then((res) => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(res + 1), 1000);
});
})
.then((res) => {
return res + 1;
})
.then((res) => {});
/**
* id: 0 resolve
* promise id: 1 第一个then函数生成的promise
* handle promise id:2 因为同步,需要执行then的success来判断函数类型,所以生成success的promise
* promise id: 3 第二个then函数生成的promise
* promise id: 4 第三个then函数生成的promise
* promise id: 5 第死个then函数生成的promise
* id: 2 resolve 第一个异步的then函数执行完成
* handle promise id:6 开始执行第二个异步的then函数,执行函数体,生成success的promise
* id: 6 resolve 第二个异步的then函数执行完成
* id: 4 resolve 第三个then函数生成的promise
* id: 5 resolve 第四个then函数生成的promise
*
*
* 可能会疑问为什么promise id为1和3的为什么没有执行resolve,这是因为1和3的promise的success返回的还是promise
* 那么就永远都不会自己执行resolve函数了
* 如果想让1和3在2和6在执行完异步操作并resolve后,也一并resolve,可以将上面注释的代码放开,就能实现。
* 主要就是在异步操作执行完,在执行defferd之前,获取父promise,清除掉他的defferd,然后执行resolve.
*/
花了差不多快一天的时间,彻底理解了该 promise 的实现原理,并做了部分修改,虽然可能花了比较多的时间,但是我觉得这还是非常值得的。
通过这次理解,我学到了如何巧妙的保存并传递 then 中回调函数,还有设计的一些思想,这里搞懂 this 的指向我觉得异常重要!