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);
});
}
}
复制代码
下一片文章我们接着来解决链式调用的问题