手写promise,了解一下(一)

JavaScript是一种属于网络的脚本语言,已经被广泛用于Web应用开发,为用户提供更流畅美观的浏览效果。

众所周知,js的事件处理模型决定了它内部很多行为都是异步的,最常见的如setTimeout、setInterval、我们通常的ajax,当然还有我们的事件,代码如:

dom.addEventListener('keydown', function(e){
   console.log(e); 
})
复制代码

这就是一段普通的键盘捕获程序,这本身当然是没什么问题的。有问题的是随着业务越来越复杂,我们需要不断的借助异步的方式处理各种各样的逻辑,然后代码就变成了这样:

ajax('requestA', function(resA){
    //do sth
    ajax('requestB', function(resB){
        //do sth
        ajax('requestC', function(resC){
            //do sth
            ajax('requestD', function(resD){
                //do sth
                ajax('requestE', function(resE){
                    //do sth
                    ajax('requestF', function(resF){
                        //do sth
                        ajax('requestG', function(resG){
                            //do sth
                            ajax('requestH', function(resH){
                                //do sth
                            })
                        })
                    })
                })            
            })        
        })    
    })    
})
复制代码

Promise的出现就是为了解决这种回调地狱。今天我们就来了解一下Promise~~

一 、初识Promise

什么是promise?

Promise可能大家都不陌生,因为Promise规范已经出来好一段时间了,同时Promise也已经纳入了ES6,而且高版本的chrome、firefox浏览器都已经原生实现了Promise,只不过和现如今流行的类Promise类库相比少些API。

所谓Promise,字面上可以理解为“承诺”,就是说A调用B,B返回一个“承诺”给A,然后A就可以在写计划的时候这么写:当B返回结果给我的时候,A执行方案S1,反之如果B因为什么原因没有给到A想要的结果,那么A执行应急方案S2,这样一来,所有的潜在风险都在A的可控范围之内了。

  我们从最基础的用法开始一步一步模仿promise的实现。      Promise是通过new来调用,而且需要传入回调函数:

var promise = new Promise(function(resolve, reject){
    //do something
});
复制代码
所以Promise是必须是一个可以构造函数:
复制代码
function Promise(executor){
    executor();
}
复制代码

Promise规范如下: 一个promise可能有三种状态:等待(pending)、已完成(fulfilled)、已拒绝(rejected)

function Promise(executor){
    var self = this;
    self.state = 'padding';//初始状态为pending

    executor();
}
复制代码
我们会在new的回调函数里改变promise的状态
复制代码
var promise = new Promise(function(resolve, reject){
    resolve();//把promise的状态改为已完成
});
复制代码

我们的源码为

function Promise(executor){
    var self = this;
    self.state = 'padding';//初始状态为pending
    
    function resolve(){
        self.state = 'resolved';
    }
    
    function reject(){
        self.state = 'rejected';
    }

    executor(resolve, reject);
}
复制代码

promise的状态只可能从“等待”转到“完成”态或者“拒绝”态,不能逆向转换,同时“完成”态和“拒绝”态不能相互转换

var promise = new Promise(function(resolve, reject){
    resolve();//把promise的状态改为已完成
    reject();//把promise的状态改为已拒绝
    //这样会2此修改promise的状态
});
复制代码

为了防止这种情况,我们修改我们的代码

function Promise(executor){
    var self = this;
    self.state = 'padding';//初始状态为pending
    
    function resolve(){
        if(self.state == 'padding'){
            self.state = 'resolved';   
        }
    }
    
    function reject(){
        if(self.state == 'padding'){
            self.state = 'rejected';
        }
    }

    executor(resolve, reject);
}
复制代码

promise必须实现then方法,then方法接受两个参数,第一个参数是成功时的回调,在promise由“等待”态转换到“完成”态时调用,另一个是失败时的回调,在promise由“等待”态转换到“拒绝”态时调用。

var promise = new Promise(function(resolve, reject){
    resolve();//把promise的状态改为已完成
});
promise.then(function(){
    console.log('promise的状态改为已完成');//控制台会打印此句
}, function(){
    console.log('promise的状态改为已拒绝');
});
复制代码
var promise = new Promise(function(resolve, reject){
    reject();//把promise的状态改为已拒绝
});
promise.then(function(){
    console.log('promise的状态改为已完成');
}, function(){
    console.log('promise的状态改为已拒绝');//控制台会打印此句
});
复制代码

我们的源码为

function Promise(executor){
    var self = this;
    self.state = 'padding';//初始状态为pending
    
    function resolve(){
        if(self.state == 'padding'){
            self.state = 'resolved';   
        }
    }
    
    function reject(){
        if(self.state == 'padding'){
            self.state = 'rejected';
        }
    }

    executor(resolve, reject);
}
Promise.prototype.then = function(onFulfilled, onRejected){
    var self = this;
    
    if(self.state = 'resolved'){
        onFulfilled();
    }
    
    if(self.state = 'rejected'){
        onRejected();
    }
}
复制代码

很多时候promise是异步的,比如

let p = new Promise(function(resolve, reject){
	setTimeout(function(){
		resolve();
	}, 3000)
});
复制代码

为了解决异步问题,我们的源码改为

function Promise(executor){
	let self = this;
	self.state = 'padding';
	self.onResolvedCallbacks = [];
	self.onRejectedCallbacks = [];

	function resolve(value){
		if(self.state == 'padding'){
			self.state = 'resolved'
			self.onResolvedCallbacks.forEach(fn=>fn());
		}	
	}

	function reject(reson){
		if(self.state == 'padding'){
			self.state = 'rejected'
			self.onRejectedCallbacks.forEach(fn=>fn());
		}
	}

	try{
		executor(resolve, reject);
	}catch(e){
		reject(e);
	}
}

Promise.prototype.then = function(onFulfilled, onRejected){
	let self = this;

	if(self.state === 'resolved'){
		onFulfilled();
	}

	if(self.state === 'rejected'){
		onRejected();
	}

	if(self.state === 'padding'){
		self.onResolvedCallbacks.push(function(){
			onFulfilled();
		});
		self.onRejectedCallbacks.push(function(){
			onRejected();
		});
	}
}
复制代码

promise规定执行then回调时,能够接收一个值,成功有成功的值,失败有失败的原因。

let p = new Promise(function(resolve, reject){
	setTimeout(function(){
		resolve('hello');
	}, 3000)
});

p.then(function(data){
	console.log(data);//打印出  hello
}, function(err){
	console.log(err);
});
复制代码

所以我们的源码改为

function Promise(executor){
	let self = this;
	self.state = 'padding';
	self.value = undefined;
	self.reson = undefined;
	self.onResolvedCallbacks = [];
	self.onRejectedCallbacks = [];

	function resolve(value){
		if(self.state == 'padding'){
			self.state = 'resolved'
			self.value = value
			self.onResolvedCallbacks.forEach(fn=>fn());
		}	
	}

	function reject(reson){
		if(self.state == 'padding'){
			self.state = 'rejected'
			self.reson = reson
			self.onRejectedCallbacks.forEach(fn=>fn());
		}
	}

	try{
		executor(resolve, reject);
	}catch(e){
		reject(e);
	}
}

Promise.prototype.then = function(onFulfilled, onRejected){
	let self = this;

	if(self.state === 'resolved'){
		onFulfilled(self.value);
	}

	if(self.state === 'rejected'){
		onRejected(self.reson);
	}

	if(self.state === 'padding'){
		self.onResolvedCallbacks.push(function(){
			onFulfilled(self.value);
		});
		self.onRejectedCallbacks.push(function(){
			onRejected(self.reson);
		});
	}
}
复制代码

下一片文章我们接着来解决链式调用的问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值