Promise 思考及强化实现
标签(空格分隔): ES6 Promise
本文原创,如需转载请注明出处
我需要什么
做了Sudoku项目后,很头疼的问题就是代码维护,很大一部分原因是回调嵌套太多,影响代码的可读性,增加了维护难度,尤其是后端的数据库操作,用nodeJs通常会写许多回调嵌套。这次终于打算揭竿起义。
第二次修改,废话不多说,直接进入正题
先看下面这段代码
function do(){
//查找数据库
setTimeout(()=>{
console.log('收到数据');
//修改字段,并保存
setTimeout(()=>{
console.log('保存成功')
//发送响应给前端
},1000)
setTimeout
},1000)
}
do()
模拟了非常简单的一个从前端接受请求到发送响应回到前端的过程,
这个代码是非常简单的,不过看起来并不是,而且一旦需求更复杂,
这样风格的代码肯定会让我非常头疼
我需要的代码风格
- 每个异步过程独立成块,不再是嵌套风格
- 异步返回结果的处理过程独立于异步过程
- 可伸缩,直接扩展异步结果处理过程,并不与之前的混在一起,实现细分,独立成块
- 每个异步过程存在依赖
好吧,发现promise满足我的所有需求,拿来现成用?这一点都不好玩
,所以研究了一下promise的用法,下面是我简易的需求说明
需求说明(参考ES6的实现效果)
- 每个promise实例 resolve动作 reject动作
- promise实例 then方法注册resolve回调,reject回调
- A实例执行完回调,then()会返回一个B实例
- B实例跟A一样,同样有 resolve动作 reject动作
- 调用B的then()方法同样会注册resolve回调,reject回调
- 影响B动作的因素有4个(下面详细讲解)
- 有catch同then一样,但是只能注册一个错误回调
- a实例如过程上依赖于另外一个b实例,则可被当做其resolve参数传递,并且b实例成功好事滚粗依赖于 a 的状态
- 一旦实例状态发生改变,状态不会再改变
影响B实例的因素
1.A的resolve回调和reject回调是否有异常抛出
是:B执行reject动作 否:B执行resolve动作
2.A的reject动作是否有回调
是:回到1. 、 否:B执行reject动作
3.A的resolve动作是否有回调
是:回到1 否: B执行resolve动作
4.A的回调中return 另一个promise实例C
C resolve: B resolve C reject: B reject
具体实现
Promise实例所有的属性
class Promise{
//构造函数 fn为构建实例的异步过程
constructor(fn){
//必须为函数类型
if(typeof fn !== 'function') throw new Error('not a function');
this.success = [];
this.sucArg = null;
this.fail = [];
this.failArg = null;
this.state = 0;
this.parent = null;
//fork promise分支
this.fork = [];
//传递的error
setTimeout(()=>{
fn(myPromise.resolve.bind(this),myPromise.reject.bind(this))
},0);
}
}
Promise实例的方法,then(),catch()
//onFulfilled成功处理函数,onRejected滚粗处理函数
then(onFulfilled,onRejected){
/*参数格式限制*/
let fork = new myPromise(()=>{});
if(typeof onFulfilled ==='function'){
this.success.push(onFulfilled);
fork.forkSuc = onFulfilled;
}
if(typeof onRejected ==='function'){
this.fail.push(onRejected);
fork.forkRej = onRejected;
}
this.fork.push(fork);
return fork;
}
catch(onRejected){
//参数必须函数
let fork = new myPromise(()=>{});
if(typeof onRejected !=='function') return this;
this.fail.push(onRejected);
fork.forkRej = onRejected;
this.fork.push(fork);
return fork;
}
Promise静态方法resolve,reject
static resolve(value){
if(this.state!==0) return;
//参数不是myPromise实例
if(value instanceof myPromise){
//如参数是一个promise实例
value.parent = this;
if(value.state===1){
//实例状态为成功
myPromise.resolve.call(this,value.successArg);
}else if(value.state===-1){
//实例状态为失败
myPromise.reject.call(this,value.failArg);
}
}else{
if(!this.success.length){
for(let fn of this.fork){
myPromise.resolve.call(fn,value);
}
}else{
this.sucArg = value;
let cur = 0;
for(let fn of this.success){ if(this.fork.length&&fn===this.fork[cur].forkSuc){
let error,preArg,bool;
try{
preArg = fn(value);
if(preArg instanceof myPromise){
let index = cur;
bool = true;
preArg.success.push(()=>{ myPromise.resolve.call(this.fork[index],preArg.sucArg);
});
preArg.fail.push(()=>{ myPromise.reject.call(this.fork[index],preArg.failArg);
})
}
}catch(err){
error = err||null;
}
if(!bool){
error? myPromise.reject.call(this.fork[cur],error): myPromise.resolve.call(this.fork[cur],preArg);
}
cur++;
}else{
fn(value);
}
}
}
//当前promise变为fulfilled
this.state = 1;
//如存在parent,则parent.resolve(value)
if(this.parent) myPromise.resolve.call(this.parent,value);
}
}
static reject(value){
if(this.state!==0) return;
//参数是myPromise实例
if(value instanceof myPromise){
value.parent = this;
myPromise.reject.call(this);
}else{
if(!this.fail.length){
for(let fn of this.fork){
myPromise.reject.call(fn,value)
}
}else{
this.failArg = value;
let cur = 0;
for(let fn of this.fail){
if(this.fork.length&&fn===this.fork[cur].forkRej){
let error,preArg,bool;
try{
preArg = fn(value);
if(preArg instanceof myPromise){
let index = cur;
bool = true;
preArg.success.push(()=>{ myPromise.resolve.call(this.fork[index],preArg.sucArg);
});
preArg.fail.push(()=>{ myPromise.reject.call(this.fork[index],preArg.failArg);
})
}
}catch(err){
error = err||null;
}
if(!bool){
error? myPromise.reject.call(this.fork[cur],error): myPromise.resolve.call(this.fork[cur],preArg);
}
cur++;
}else{
fn(value);
}
}
}
this.state = -1;
if(this.parent) myPromise.reject.call(this.parent,value);
}
}
好了,就这么多,这是个简易的Promise实现,如有错误,或者什么建议
QQ:387857274欢迎讨论