promise承诺,是es6一个非常重要的解决回调地狱的工具,其本质就是个观察者模式。其实现思路是:
在then注册事件,通过resolve或reject触发事件。
今天我们就试着手写一个简版的promise,对大家理解promise更有帮助。
第一步:整体框架
我们先搭一个promise的整体框架:
function myPromise(callback){
function resolve(){
console.log('ok')
}
function reject(){
console.log('error')
}
callback(resolve,reject)
}
let p = new myPromise(function(resolve,reject){
setTimeout(function(){
resolve()
},500)
})
别小看这段代码,这里涉及到高阶函数的概念,请大家仔细咂摸一下。如果实在看不明白也不要紧,那先看个简单的:
let convert = function(val,fn){
//转换val值,fn是转换规则
return fn(val)
}
let toInt = function(val){
return parseInt(val)
}
let res = convert('100.2',toInt)
console.log(res)
高阶函数的高阶,就是往上走,先不执行,其实就是延迟执行。
第二步:填充属性
框架有了,下面需要准备一些必备属性了。
观察者模式大家想必都比较熟悉,我们起码需要一个数组,用来存放待触发的函数。
promise需要的属性清单是:
1、两个数组,分别存放成功和失败两种情况下待触发的函数。
2、状态属性,因为promise有三种状态,分别是:pending、resolve和reject。
3、成功和失败的value信息。
好,我们再完善一下代码:
function myPromise(callback){
var self = this;
self.status = 'pending'//状态位
self.onFulfilledCallbacks = []//存放成功触发的函数
self.onRejectedCallbacks = []//存放失败触发的函数
self.value = null//成功的返回值
self.reason = null//失败的返回值
function resolve(value){
if(self.status === 'pending'){
self.status = 'fulfilled'
self.value = value;
self.onFulfilledCallbacks.forEach(fn=>fn())
}
}
function reject(reason){
if(self.status === 'pending'){
self.status = 'rejected'
self.reason = reason;
self.onRejectedCallbacks.forEach(fn=>fn())
}
}
try{
callback(resolve,reject) //执行高阶函数
}catch(err){
reject(err)
}
}
第三步:then函数
then就是用来注册待触发的函数。
myPromise.prototype.then = function(onFulfilled,onRejected){
let self = this;
if(self.status === 'pending'){
self.onFulfilledCallbacks.push(function(){
onFulfilled(self.value)
})
self.onRejectedCallbacks.push(function(){
onRejected(self.reason)
})
}
}
第四步:测试一下
function myPromise(callback){
var self = this;
self.status = 'pending'
self.onFulfilledCallbacks = []
self.onRejectedCallbacks = []
self.value = null
self.reason = null
function resolve(value){
if(self.status === 'pending'){
self.status = 'fulfilled'
self.value = value;
self.onFulfilledCallbacks.forEach(fn=>fn())
}
}
function reject(reason){
if(self.status === 'pending'){
self.status = 'rejected'
self.reason = reason;
self.onRejectedCallbacks.forEach(fn=>fn())
}
}
try{
callback(resolve,reject) //执行高阶函数
}catch(err){
reject(err)
}
}
myPromise.prototype.then = function(onFulfilled,onRejected){
let self = this;
if(self.status === 'pending'){
self.onFulfilledCallbacks.push(function(){
onFulfilled(self.value)
})
self.onRejectedCallbacks.push(function(){
onRejected(self.reason)
})
}
}
new myPromise(function(resolve,reject){
setTimeout(function(){
resolve({code:200,data:'ok'})
},500)
}).then(function(res){
console.log(res)
})
第五步:修正
还有点小瑕疵不知道大家注意到木有:
new myPromise(function(resolve,reject){
resolve({code:200,data:'ok'})
}).then(function(res){
console.log(res)
})
如果resolve函数是立即执行而不是延时的话,那再往缓存数组里面丢就没意义了,这种情况我们需要在then函数内部单独判断一下:
myPromise.prototype.then = function(onFulfilled,onRejected){
let self = this;
if(self.status === 'pending'){
self.onFulfilledCallbacks.push(function(){
onFulfilled(self.value)
})
self.onRejectedCallbacks.push(function(){
onRejected(self.reason)
})
}
//立即执行的情况
if(self.status==='fulfilled'){
onFulfilled(self.value)
}
//立即执行的情况
if(self.status === 'rejected'){
onRejected(self.value)
}
}
第六步:完整版
function myPromise(callback){
var self = this;
self.status = 'pending'
self.onFulfilledCallbacks = []
self.onRejectedCallbacks = []
self.value = null
self.reason = null
function resolve(value){
if(self.status === 'pending'){
self.status = 'fulfilled'
self.value = value;
self.onFulfilledCallbacks.forEach(fn=>fn())
}
}
function reject(reason){
if(self.status === 'pending'){
self.status = 'rejected'
self.reason = reason;
self.onRejectedCallbacks.forEach(fn=>fn())
}
}
try{
callback(resolve,reject) //执行高阶函数
}catch(err){
reject(err)
}
}
myPromise.prototype.then = function(onFulfilled,onRejected){
let self = this;
if(self.status === 'pending'){
self.onFulfilledCallbacks.push(function(){
onFulfilled(self.value)
})
self.onRejectedCallbacks.push(function(){
onRejected(self.reason)
})
}
if(self.status==='fulfilled'){
onFulfilled(self.value)
}
if(self.status === 'rejected'){
onRejected(self.value)
}
}
new myPromise(function(resolve,reject){
resolve({code:200,data:'ok'})
}).then(function(res){
console.log(res)
})
当然真实的promise比这复杂的多,手写的意义在于加深理解,而不是炫技,重复创造是毫无意义的。
网友评论