说到promise就会想到下面几个疑问。
1、为什么会出现promise
2、它的作用是什么?
3、它的原理是什么,怎么实现的呢?
既然知道了问题点,就可以一个个的解决它
为什么会有promise?
// 一个简单的示例 执行一个动画A,执行完之后再去执行另一个动画B
setTimeout(function(){
console.log('A'); //A动画
setTimeout(function() {
console.log('B'); // //B动画
},300)
},300);
// 这里只有两个动画,如果有更多呢,就会看到一堆函数缩进
很明显,如果有更多的动画,就会使代码横向发展而非纵向发展。乱成一团,很难管理。多个异步操作形成了强耦合,只要有一个操作修改,它的上层回调和下层回调可能都会修改,这种情况称之为“回调函数地域(callback hell)”。promise的出现解决了这个问题,它允许将函数嵌套改成链式调用,使我们可以像写同步代码一样去写异步代码。
注:promise不是新的语法功能,是一种新的写法
promise的原理
promise其实就是三个状态,利用观察者模式通过特殊的手写方式注册对应状态的事件处理函数,然后改变状态,调用处理函数
特殊的方式:
- .done 成功处理函数列表
- .fail 失败处理函数列表
- .then 同时注册成功与失败处理函数
- .always 一个对象从注册到成功和失败
更新状态
- pending(等待)
- resolved(成功)
- rejected(失败)
如何实现,那就来看代码把~
/*
* state状态:PENDING、RESOLVED、REJECTED
* .doneList 成功处理函数列表
* .failList 失败处理函数列表
* .done 注册成功处理函数
* .fail 注册失败处理函数
* .then 同时注册成功和失败的处理函数
* .always 一个对象从等待到成功和失败
* .resolved 更新state状态为resolved,并执行成功处理序列
* .rejected 更新state状态为rejected,并执行失败处理序
*/
class MyPromise{
constructor(fn){
this.state = "PENDING";
this.doneList = []
this.failList = []
fn(this.resolve.bind(this),this.reject.bind(this)) // 确保this指向正确
}
done(handle){
if(typeof handle === 'funciton'){
this.doneList.push(handle)
}else{
throw new Error('缺少回调函数');
}
return this
}
fail(handle){
if(typeof handle === 'function'){
this.failList.push(handle)
}else{
throw new Error('没有回调函数')
}
return this
}
then(success,fail){
this.done(success || function(){})
.fail(fail || function(){})
return this
}
always(handle){
this.done(handle || function(){})
.fail(handle || function(){})
return this
}
//doneList中第一个函数的返回值是第二个函数的参数,第二个函数的返回值是第三个函数的参数。failList同理。
resolve(...cbs){
if(this.state === 'PENDING'){
this.state = "RESOLVED"
setTimeout(()=>{
this.doneList.forEach((fn)=>{
sth = fn.apply(null,cbs)
})
},0)
return this
}
}
reject(...cbs){
if(this.state === 'PENDING'){
this.state = "REJECTED"
setTimeout(()=>{
this.failList.forEach((fn)=>{
sth = fn.apply(null,cbs)
})
},0)
return this
}
}
}
new MyPromise((resolve,reject)=>{
resolve('MyPromise --- You Are Right')
// reject('MyPromise --- You Are Error')
}).then(
success => {
console.log(success)
},
fail => {
console.log(fail)
}
)
解释: 当我们调用new MyPromise(fn)时,就会立即执行第一个参数fn。上面案例中,先将then(done,fail)对应的回调函数分别加入到doneList或者failList中,always中对应的参数同时加到doneList和failList中;
当异步代码执行完毕,就调用resolve方法,此时改变promise的状态为resolved,并执行doneList里面的回调函数。如果执行失败,则调用fail方法,此时改变promise的状态为rejected,并执行failList里面的回调函数。