一个 Promise有以下几种状态:
pending: 初始状态,既不是成功,也不是失败状态。
fulfilled: 意味着操作成功完成。
rejected: 意味着操作失败。
我们先实现下面这种效果:
new MyPromise(function(resolve,reject){
resolve(123)
}).then((v)=>{
console.log(v);//123
});
MyPromise类
class MyPromise(){
static PNEDING='pending';
static RESOLVED='funfilled';
static REJECTED='rejected';
constructor(executor){
this.status=MyPromise.PNEDING;
this.resolveCallback=[];
this.rejectCallback=[];
try {
executor(this.resolve.bind(this),this.reject.bind(this));
} catch (error) {
this.reject(error)
}
}
resolve(){...}
reject(){...}
then(){...}
}
then函数
主要任务是完成回调和失败回调的收集,分别存放完成队列和失败队列
then(onFulfilled,onRejected){
switch (this.status) {
case MyPromise.PNEDING:
this.resolveCallback.push(onFulfilled);
this.rejectCallback.push(onRejected);
break
case MyPromise.RESOLVED:
onFulfilled(this.value)
break
case MyPromise.REJECTED:
onRejected(this.value)
break
}
}
resolve函数
主要任务是触发完成队列,里面的所有回调函数
resolve(value){
this.resolveCallback.forEach(cb=>cb(value))
}
问题来了,由于resolve是立即执行的,所以此时完成队列中还没存在完成回调,所以需要放在下一个事件循环,以确保then函数收集依赖完成,解决方案:
resolve(value){
setTimeout(() => {
this.resolveCallback.forEach(cb=>cb(value))
}, 0);
}
如果resolve是MyPromises的一个实例,这种效果:
new MyPromise(function(resolve,reject){
resolve(new MyPromise(function(resolve,reject){
resolve(456)
}))
}).then((v)=>{
console.log(v);//456
});
解决方案:
resolve(value){
if(value instanceof MyPromise){
//递归,如果resolve的值是一个Promise对象的话,
返回的值是这个对象的resolve值。
return value.then(this.resolve.bind(this)
,this.reject.bind(this))
}
setTimeout(() => {
this.resolveCallback.forEach(cb=>cb(value))
}, 0);
}
reject函数
主线任务是触发失败队列,里面的所有回调函数,与resolve流程类似
reject(value){
setTimeout(() => {
this.resolveCallback.forEach(cb=>cb(value))
}, 0);
}
我们汇总一下代码:
class MyPromise{
static PNEDING='pending';
static RESOLVED='funfilled';
static REJECTED='rejected';
constructor(executor){
this.status=MyPromise.PNEDING;
this.resolveCallback=[];
this.rejectCallback=[];
try {
executor(this.resolve.bind(this),this.reject.bind(this));
} catch (error) {
this.reject(error)
}
}
resolve(value){
if(value instanceof MyPromise){
return value.then(this.resolve.bind(this)
,this.reject.bind(this))
}
setTimeout(() => {
this.resolveCallback.forEach(cb=>cb(value))
}, 0);
}
reject(value){
setTimeout(() => {
this.resolveCallback.forEach(cb=>cb(value))
}, 0);
}
then(onFulfilled,onRejected){
switch (this.status) {
case MyPromise.PNEDING:
this.resolveCallback.push(onFulfilled);
this.rejectCallback.push(onRejected);
break
case MyPromise.RESOLVED:
onFulfilled(this.value)
break
case MyPromise.REJECTED:
onRejected(this.value)
break
}
}
}
链式调用
如果我们要实现链式调用,我们改造一下then函数
then(onFulfilled,onRejected){
switch (this.status) {
case MyPromise.PNEDING:
this.resolveCallback.push(onFulfilled);
this.rejectCallback.push(onRejected);
break
case MyPromise.RESOLVED:
onFulfilled(this.value)
break
case MyPromise.REJECTED:
onRejected(this.value)
break
}
return this;//返回自己
}
效果:
new MyPromise(function(resolve,reject){
resolve(456)
}).then((v)=>{
console.log(v);//456
}).then((v)=>{
console.log(v);//456
});
我们发现这里出现问题了,打印出来了两个456,理论上是456,undefind,回调对列前一个函数的值是后一个函数的入参,所以我们可以用return,把我们获取的值,向下一个then函数传递
resolve(value){
if(value instanceof MyPromise){
return value.then(this.resolve.bind(this),
this.reject.bind(this))
}
setTimeout(() => {
if(this.status==MyPromise.PNEDING){
this.status=MyPromise.RESOLVED;
this.value=value;
this.resolveCallback.forEach(cb=>this.value=cb(this.value))
}
}, 0);
}
下列情况我们需要优化一下resolve函数,理论上123不会在调用,因为此时Mypromise已经是fulfilled状态
let p=new MyPromise(function(resolve,reject){
resolve(456)
}).then((v)=>{
console.log(v);//456
}).then((v)=>{
console.log(v);//456
});
p.resolve(123);//123
优化代码如下:
resolve(value){
if(value instanceof MyPromise){
return value.then(this.resolve.bind(this)
,this.reject.bind(this))
}
setTimeout(() => {
if(this.status===MyPromise.PNEDING){
this.status=MyPromise.RESOLVED;
this.value=value;
this.resolveCallback.forEach(cb=>this.value=cb(this.value))
}
}, 0);
}
reject函数类似:
reject(value){
if(this.status===MyPromise.PNEDING){
this.status=MyPromise.REJECTED
this.value=value
setTimeout(() => {
this.resolveCallback.forEach(cb=>cb(value))
}, 0);
}
}
完整代码
到此,简单的promise已经具备,then,resolve,reject函数功能:
class MyPromise{
static PNEDING='pending';
static RESOLVED='funfilled';
static REJECTED='rejected';
constructor(executor){
this.status=MyPromise.PNEDING;
this.value=null;
this.resolveCallback=[];
this.rejectCallback=[];
try {
executor(this.resolve.bind(this),this.reject.bind(this));
} catch (error) {
this.reject(error)
}
}
resolve(value){
if(value instanceof MyPromise){
return value.then(this.resolve.bind(this)
,this.reject.bind(this))
}
setTimeout(() => {
if(this.status===MyPromise.PNEDING){
this.status=MyPromise.RESOLVED;
this.value=value;
this.resolveCallback.forEach(cb=>this.value=cb(this.value))
}
}, 0);
}
reject(value){
if(this.status===MyPromise.PNEDING){
this.status=MyPromise.REJECTED
this.value=value
setTimeout(() => {
this.resolveCallback.forEach(cb=>cb(value))
}, 0);
}
}
then(onFulfilled,onRejected){
switch (this.status) {
case MyPromise.PNEDING:
this.resolveCallback.push(onFulfilled);
this.rejectCallback.push(onRejected);
break
case MyPromise.RESOLVED:
onFulfilled(this.value)
break
case MyPromise.REJECTED:
onRejected(this.value)
break
}
return this;
}
}
let p=new MyPromise(function(resolve,reject){
resolve(456)
}).then((v)=>{
console.log(v);//456
}).then((v)=>{
console.log(v);//undefind
});
下一篇我们会继续对promise的,静态方法实现,catch函数等进行实现;