JS异步编程学习笔记三:动手封装一个Promise

95 阅读3分钟

实现then的流程处理

1、实现promise中同步代码的执行

首先创建一个函数myPromise,传入resolve,reject参数,利用回调函数实现promise中同步代码的执行

 function myPromise(fn) {
     var resolve = function(Value) {
         return Value
     }
     var reject = function(errValue) {
                return errValue
      }
      if (fn) {
         fn(resolve, reject)
      }
 }

调用函数看结果

var p = new myPromise(function(resolve, reject) {
            console.log('我是同步执行的');
        })

2、实现promise的状态

promise有三种状态promiseState:

  • 初始状态pending
  • 成功的状态:fulfilled
  • 失败的状态:rejected

PromiseResult属性

  • 默认值:undefined
  • resolve或 reject 触发时传递的参数
//实现promise的状态和结果(默认)
this.PromiseState = 'pending'
this.PromiseResult = undefined
//更改this指向
let _this = this
var resolve = function(Value) {
    //实现promise的状态(resolve)
    if (_this.PromiseState === 'pending') { //控制只能执行一次
         _this.PromiseState = 'fulfilled'
          _this.PromiseResult = Value
    }
    return Value
 }

3、实现resolve执行触发.then()执行

初始化.then()函数

myPromise.prototype.then = function(callback) { }

定义一个函数变量,利用回调函数,使用setTimeout异步执行

this.thenCallback = undefined

var resolve = function(Value) {
  //实现promise的状态(resolve)
  if (_this.PromiseState === 'pending') { //控制只能执行一次
        _this.PromiseState = 'fulfilled'
        _this.PromiseResult = Value
        //异步执行,肯定在同步执行完成之后执行
        setTimeout(function() {
           if (_this.thenCallback) {
               _this.thenCallback(Value) //执行thenCallback 函数
           }
        })
   }
   return Value
}

//实现.then : 初始化.then 函数
myPromise.prototype.then = function(callback) {
// 因为是同步任务,所有resolve之后会将  thenCallback 由 undefine赋值为一个函数
   _this.thenCallback = function(value) {
    callback(value) //目的是将resolve的参数传递给then作为参数
   }
}

4、实现.then().then()...链式调用

当上个then()返回的参数是普通字符串

myPromise.prototype.then = function(callback) {
     //实现链式调用时,每个.then 都应是一个promise对象 
  return new myPromise(function(resolve, reject) {
     // 因为是同步任务,所有resolve之后会将  thenCallback 由 undefine赋值为一个函数
     _this.thenCallback = function(value) {
          var res = callback(value) //目的是将resolve的参数传递给then作为参数
          resolve(res)
     }
  })
}

当上个then()返回的参数是一个promise对象

// 当then传入的类型是myPromise对象时;
if (Value instanceof myPromise) {
    Value.then(function(res) {
        if (_this.thenCallback) {
             _this.thenCallback(res)
        }
    })
} else {
    setTimeout(function() {
       if (_this.thenCallback) { //添加判断防止没有写.then()的情况
           _this.thenCallback(Value) //执行thenCallback 函数
        }
    })
}

最后调用我们封装的myPromise做测试,查看输出结果

var p = new myPromise(function(resolve, reject) {
            resolve('resolve的值')
            console.log('我是同步执行的');
        })
p.then(function(res) {
   console.log("第一个then", res);
   return 123
}).then(function(res) {
   console.log("第二个then", res);
   return new myPromise(function(resolve, reject) {
      resolve(456)
   })
}).then(function(res) {
   console.log("第三个then", res);
   return 789
}).then(function(res) {
   console.log("第四个then", res);
})

实现catch的流程处理

1、同以上then类似,实现.catch()流程

仿照then的方式在myPromise对象中定义好初始通知函数

this.catchCallback = undefined
var reject = function(errValue) {
    if (_this.PromiseState === 'pending') {
          _this.PromiseState = 'rejected'
          _this.PromiseResult = errValue
    }
    setTimeout(function() {
         if (_this.catchCallback) {
             _this.catchCallback(errValue)
         } else {
             //防止返回reject 但是没有写catch的情况报错
              throw ('promise执行了reject,但是没有注册catch!')
         }
     })
     return errValue
}

然后在catch函数中处理

myPromise.prototype.catch = function(callback) {
     var _this = this
     return new myPromise(function(resolve, reject) {
         _this.catchCallback = function(value) {
            var err = callback(value)
            resolve(err)
         }
     })
}

2、考虑到.then.catch()中,catch的触发

写完以上的代码会发现,myPromise调用reject的时候,p.catch()执行了,但是p.then().catch()仍然没有执行。

这是因为myPromise调用reject的时候,promise的对象会变更成rejected的状态,并且catch的回调函数无法注册

所以需要追加判断代码让promise值rejected的时候如果没有catchCallback是再去检查是否存在thenCallback

//reject中
setTimeout(function() {
   if (_this.catchCallback) {
       _this.catchCallback(errValue)
   } else if (_this.thenCallback) {
       _this.thenCallback(errValue)
   } else {
      throw ('promise执行了reject,但是没有注册catch!')
   }
})

更改then函数中的逻辑

_this.thenCallback = function(value){
    //判断如果进⼊该回调时Promise的状态为rejected那么就直接触发后续Promise的catchCallback
    //直到找到catch
    if(_this.promiseState == 'rejected'){
       reject(value)       //执行一个catch后就不会在往下执行了
    }else{
       var callbackRes = callback(value)
       resolve(callbackRes)
    }
}

3、考虑到链式调用的中断

即考虑 .then中返回promise.reject()的情况

处理 promise返回resolve 时,先执行了.then() , then中返回的new Promise 的 rejected()

更改then中关键代码

if (_this.PromiseState === 'rejected') {
     reject(value) //执行一个catch后就不会在往下执行了
} else if (callback) {
     var res = callback(value) //目的是将resolve的参数传递给then作为参数
     //最后一步:实现then链式调用时某一个then返回promise.reject()中断的情况
     if (res instanceof myPromise) {
           if (res.PromiseState === 'rejected') {
              res.catch(function(errValue) {
                 reject(errValue)
              })
           } else {
              resolve(res)
           }
      } else {
           resolve(res)
      }
}