JavaScript基础:手写Promise(1)

在这里插入图片描述

一、构建

本次推文将会手写开发Promise实现,提升异步编程的能力。

首先声明定义类并声明Promise状态与值,有以下几个细节需要注意。

  • executor为执行者
  • 当执行者出现异常时触发拒绝状态
  • 使用静态属性保存状态值
  • 状态只能改变一次,所以在resolvereject添加条件判断
  • 因为 resolverejected方法在executor中调用,作用域也是executor作用域,这会造成this指向window,现在我们使用的是class定义,thisundefined
class MyPromise{
    static PENDING = 'pending';
	static FULFILLED = 'fulfilled';
	static REJECTED = 'rejected';
	constructor(executor){
        this.status = MyPromise.PENDING;
        this.value = null;
        try{
            executor(this.resolve.bind(this),this.reject.bind(this));
        } catch{
            this.reject(error);
        }
    }
	resolve(value){
        if(this.status == MyPromise.PENDING){
            this.status = MyPromise.FULFILLED;
            this.value = value;
        }
    }
	reject(value){
        if(this.status == MyPromise.PENDING){
            this.status = MyPromise.REJECTED;
            this.value = value;
        }
    }
}

案例代码测试:

<script src ="MyPromise.js"></script>
<script>
    let goodJob = new MyPromise((resolve,reject)=>{
        resolve("前端收割机!!!!")
    });
    console.log(goodJob); //前端收割机!!!!
</script>

二、THEN

现在添加then方法来处理状态的改变,有以下几点说明

  1. then可以有两个参数,即成功和错误时的回调函数
  2. then的函数参数都不是必须的,所以需要设置默认值为函数,用于处理当没有传递时情况
  3. 当执行then传递的函数发生异常时,统一交给onRejected来处理错误
1.基础构建
then(onFulfilled,onRejected){
    if(typeof onFulfilled != "function"){
        onFulfilled = value => value;
    }
    if(typeof onRejected != "function"){
        onRejected = value => value;
    }
    if(this.status == MyPromise.FULFILLED){
        try{
            onFulfilled(this.value);
        } catch{
            onRejected(error);
        }
    }
    if(this.status == MyPromise.REJECTED){
        try{
            onRejected(this.value);
        } catch{
            onRejected(error);
        }
    }
}

案例代码测试(then方法代码放进MyPromise类中):

<script src ="MyPromise.js"></script>
<script>
    let goodJob = new MyPromise((resolve,reject)=>{
        resolve("前端收割机!!!!")
    }).then(
        value =>{
            console.log(value);
        },
        reason =>{
            console.log(reason);
        }
    );
	console.log("我是主线程执行的console.log!");

	// 前端收割机!!!!
	// 我是主线程执行的console.log!
</script>
2.异步任务

前面代码中的then方法可以正常执行,但代码产生的Promise并不是异步的,所以我们需要使用setTimeout来将onFulfilledonRejected做为异步宏任务执行。

then(onFulfilled,onRejected){
    if(typeof onFulfilled != "function"){
        onFulfilled = value => value;
    }
    if(typeof onRejected != "function"){
        onRejected = value => value;
    }
    if(this.status == MyPromise.FULFILLED){
        setTimeout(()=>{
            try{
                onFulfilled(this.value);
            } catch(error){
                onRejected(error);
            }
        });
    }
    if(this.status == MyPromise.REJECTED){
        setTimeout(()=>{
            try{
                onRejected(this.value);
            } catch{
                onRejected(error);
            }
        });
    }
}

案例代码测试(Promise异步执行):

<script src ="MyPromise.js"></script>
<script>
    let goodJob = new MyPromise((resolve,reject)=>{
        resolve("前端收割机!!!!")
    }).then(
        value =>{
            console.log(value);
        },
        reason =>{
            console.log(reason);
        }
    );
	console.log("我是主线程执行的console.log!");

	// 我是主线程执行的console.log!
	// 前端收割机!!!!
</script>
3.PENDING状态

目前then方法无法处理promise为pending时的状态

...
let goodJob = new MyPromise((resolve,reject)=>{
    setTimeout(()=>{
        resolve("前端收割机!!!!");
    });
})
...

所以为了处理上述情况,需要进行几点改动

  • 在构造函数中添加callback来保存pending状态时的处理函数,当状态改变时循环调用。

    constructor(executor){
        ...
        this.callbacks = [];
        ...
    }
    
  • 将then方法的回调函数添加到callback数组中,用于异步执行。

    then(onFulfilled,onRejected){
        if(typeof onFulfilled != "function"){
            onFulfilled = value => value;
        }
        if(typeof onRejected != "function"){
            onRejected = value => value;
        }
        if(this.status == MyPromise.PENDING){
            this.callbacks.push({
                onFulfilled: value =>{
                    try{
                        onFulfilled(value);
                    } catch(error){
                        onRejected(error);
                    }
                },
                onRejected: value =>{
                    try{
                        onRejected(value);
                    } catch(error){
                        onRejected(error);
                    }
                }
            });
        }
        ...
    }
    
  • resolve方法和reject方法中添加处理callback方法的代码。

  resolve(value){
      if(this.status == MyPromise.PENDING){
          this.status = MyPromise.FULFILLED;
          this.value = value;
          this.callbacks.map(callback =>{
              callback.onFulfilled(value);
          });
      }
  }
  reject(value){
      if(this.status == MyPromise.PENDING){
          this.status = MyPromise.REJECTED;
          this.value = value;
          this.callbacks.map(callback =>{
              callback.onRejected(value);
          });
      }
  }
4.PENDING异步

执行以下代码发现并不是异步操作,应该先输出 “我要先执行!” 然后是 “前端收割机!!!!”。

<script src ="MyPromise.js"></script>
<script>
    let goodJob = new MyPromise((resolve,reject)=>{
        setTimeout(()=>{
            resolve("前端收割机!!!!")
        	console.log("我要先执行!");
        })
    }).then(
        value =>{
            console.log(value);
        },
        reason =>{
            console.log(reason);
        }
    );

	// 前端收割机!!!!
	// 我要先执行!
</script>

解决以上问题,只需要将resolvereject执行通过setTimeout定义为异步任务。

resolve(value){
    if(this.status == MyPromise.PENDING){
        this.status = MyPromise.FULFILLED;
        this.value = value;
        setTimeout(()=>{
            this.callbacks.map(callback =>{
            	callback.onFulfilled(value);
        	});
        })
    }
}
reject(value){
    if(this.status == MyPromise.PENDING){
        this.status = MyPromise.REJECTED;
        this.value = value;
        setTimeout(()=>{
            this.callbacks.map(callback =>{
            	callback.onRejected(value);
        	});
        })
    }
}

三、链式操作

Promise中的then是链式调用执行的,所以then也要返回Promise才能实现

  1. then的onReject函数是对前面Promise的rejected的处理
  2. 但该Promise返回状态要为fulfilled,所以在调用onRejected后改变当前promise为fulfilled状态
then(onFulfilled,onRejected) {
    if(typeof onFulfilled != "function"){
        onFullfilled = value =>value;
    }
    if(typeof onRejected != "function"){
        onRejected = value => value;
    }
    return new MyPromise((resolve,reject) =>{
        if(this.status == MyPromise.PENDING){
            this.callbacks.push({
                onFUlfilled: value =>{
                    try{
                        let  result = onFulfilled(value);
                        resolve(result);
                    } catch(error){
                        reject(error);
                    }
                },
                onRejected: value =>{
                    try{
                        let result = onRejected(value);
                        resolve(result);
                    } catch(error){
                        reject(error);
                    }
                }
            });
        }
        if(this.status == MyPromise.FULFILLED){
            setTimeout(()=>{
                try{
                    let result = onFulfilled(this.value);
                    resolve(result);
                } catch(error){
                    reject(error);
                }
            });
        }
        if(this.status == MyPromise.REJECTED){
            setTime(()=>{
                try{
                    let result = onRejected(this.value);
                    resolve(result);
                } catch(error){
                    reject(error);
                }
            });
        }
    });
}

案例代码测试:

<script src ="MyPromise.js"></script>
<script>
    let goodJob = new MyPromise((resolve,reject)=>{
        setTimeout(()=>{
            resolve("前端收割机!!!!")
        	console.log("我要先执行!");
        })
    }).then(
        value =>{
            console.log(value);
            return value;
        },
        reason =>{
            console.log(reason);
        }
    ).then(
        value =>{
            console.log(value);
        },
        reason =>{
            console.log(reason);
        }
    )

	// 我要先执行!
	// 前端收割机!!!!
	// 前端收割机!!!!
</script>

四、返回类型

如果then返回的值为Promise,我们需要如何处理?所以我们需要判断分别处理返回值为Promise与普通值的情况。

  • 基本实现
then(onFulfilled,onRejected) {
    if(typeof onFulfilled != "function"){
        onFullfilled = value =>value;
    }
    if(typeof onRejected != "function"){
        onRejected = value => value;
    }
    return new MyPromise((resolve,reject) =>{
        if(this.status == MyPromise.PENDING){
            this.callbacks.push({
                onFUlfilled: value =>{
                    try{
                        let  result = onFulfilled(value);
                        if(result instanceof MyPromise){
                            result.then(resolve,reject);
                        }else{
                            resolve(result);
                        }
                    } catch(error){
                        reject(error);
                    }
                },
                onRejected: value =>{
                    try{
                        let result = onRejected(value);
                        if(result instanceof MyPromise){
                            result.then(resolve,reject);
                        }else{
                            resolve(result);
                        }
                    } catch(error){
                        reject(error);
                    }
                }
            });
        }
        if(this.status == MyPromise.FULFILLED){
            setTimeout(()=>{
                try{
                    let result = onFulfilled(this.value);
                    if(result instanceof MyPromise){
                         result.then(resolve,reject);
                    }else{
                         resolve(result);
                    }
                } catch(error){
                    reject(error);
                }
            });
        }
        if(this.status == MyPromise.REJECTED){
            setTime(()=>{
                try{
                    let result = onRejected(this.value);
                    if(result instanceof MyPromise){
                         result.then(resolve,reject);
                    }else{
                         resolve(result);
                    }
                } catch(error){
                    reject(error);
                }
            });
        }
    });
}
  • 代码复用

现在发现penddingfulfilledrejected 状态的代码非常相似,所以可以提取出方法Parse来复用

then(onFulfilled,onRejected) {
    if(typeof onFulfilled != "function"){
        onFullfilled = value =>value;
    }
    if(typeof onRejected != "function"){
        onRejected = value => value;
    }
    return new MyPromise((resolve,reject) =>{
        if(this.status == MyPromise.PENDING){
            this.callbacks.push({
                onFUlfilled: value =>{
                    this.parse(onFulfilled(this.value),resolve,reject);
                },
                onRejected: value =>{
                    this.parse(onRejected(this.value),resolve,reject);
                }
            });
        }
        if(this.status == MyPromise.FULFILLED){
            setTimeout(()=>{
                this.parse(onFulfilled(this.value),resolve,reject);
            });
        }
        if(this.status == MyPromise.REJECTED){
            setTime(()=>{
                this.parse(onRejected(this.value),resolve,reject);
            });
        }
    });
}
parse(result,resolve,reject){
    try{
        if(result instanceof MyPromise){
            result.then(resolve,reject);
        }else{
            resolve(result);
        }
    } catch(error){
        reject(error);
    }
}
  • 返回约束

then的返回的promise不能是then相同的Promise,下面是原生Promise的示例将产生错误

let promise = new Promise(resolve => {
  setTimeout(() => {
    resolve("前端收割机!!!!");
  });
});
promise = promise.then(value => {
  return promise;
});

//error : Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>

解决上面的问题来完善代码,添加当前promise做为parse的第一个参数与函数结果比对

then(onFulfilled,onRejected) {
    if(typeof onFulfilled != "function"){
        onFullfilled = value =>value;
    }
    if(typeof onRejected != "function"){
        onRejected = value => value;
    }
    let promise = new MyPromise((resolve,reject) =>{
        if(this.status == MyPromise.PENDING){
            this.callbacks.push({
                onFUlfilled: value =>{
                    this.parse(onFulfilled(this.value),resolve,reject);
                },
                onRejected: value =>{
                    this.parse(onRejected(this.value),resolve,reject);
                }
            });
        }
        if(this.status == MyPromise.FULFILLED){
            setTimeout(()=>{
                this.parse(onFulfilled(this.value),resolve,reject);
            });
        }
        if(this.status == MyPromise.REJECTED){
            setTime(()=>{
                this.parse(onRejected(this.value),resolve,reject);
            });
        }
    });
    return promise;
}
parse(result,resolve,reject){
    try{
        if(result instanceof MyPromise){
            result.then(resolve,reject);
        }else{
            resolve(result);
        }
    } catch(error){
        reject(error);
    }
}

案例测试(现在进行测试也可以得到原生一样效果了)

<script src ="MyPromise.js"></script>
<script>
    let goodJob = new MyPromise(resolve => {
    	resolve("前端收割机!!!!");
	});
	goodJob = goodJob.then(value => {
  		return goodJob;
	});
	
	//error : Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>
</script>
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值