【JavaScript】细说Promise自定义封装

Promise初始结构搭建

 let p = new Promise((resolve,reject)=>{
    resolve('OK')
    })
    p.then(value=>{
        console.log(value);
    },reason=>{
        console.warn(reason);
    })
  • 参考原始Promise对象中的结构,构造函数Promise中包含一个执行器函数,原型上有then方法,该方法接收两个函数参数
  • 搭建好结构:
function myPromise(executor){

}

myPromise.prototype.then = function(onResolved,onRejected){

}

resolve与reject结构搭建

  • 考虑到Promise对象中的执行器函数是同步调用的,并且具有两个函数参数(resolve, reject),需要对这两个函数在构造函数内部进行声明,考虑到原始构造中函数有传递参数值data
function myPromise(executor){
	function resolve(data){

    }

    function reject(data){

    }
    // 同步调用执行器函数
    executor(resolve, reject)
}

resolve与reject代码实现

  • 首先分析resolve实现效果:
  1. promise状态会发生改变
  2. 设置成功的结果
  • 为了给实例对象表示状态的转变以及数据的传输,需要设定两个值
function myPromise(executor){
    //为实例对象添加属性
    this.promiseState = 'pendinng'
    this.promiseResult = null
    function resolve(data){
        //1.修改对象的状态 (promiseState)
        this.promiseState = 'fulfilled'
        //2.设置对象结果值 (promiseResult)
        this.promiseResult = data
    }
  • 若直接如上方式书写,this的指向会指向window而非实例对象
  • 因此需要保存实例对象的this值
function myPromise(executor){
    //为实例对象添加属性
    this.promiseState = 'pendinng'
    this.promiseResult = null
    //保存实例对象的this
    const self = this  //可用self _this that 表示
    function resolve(data){
        //1.修改对象的状态 (promiseState)
        self.promiseState = 'fulfilled'
        //2.设置对象结果值 (promiseResult)
        self.promiseResult = data
    }
}
  • reject函数同理
function reject(data){
        //1.修改对象的状态 (promiseState)
        self.promiseState = 'rejected'
        //2.设置对象结果值 (promiseResult)
        self.promiseResult = data
    }

throw抛出异常改变状态

  • 抛出错误后应返回一个失败的Promise对象
 let p = new Promise((resolve,reject)=>{
    //resolve('OK')
    throw "error"
    })
console.log(p) 
  • 如何处理throw?想到try..catch..方法
  • 往哪里加try..catch..?考虑到是在执行器函数内部执行,通过catch捕捉的throw后,调用reject函数修改状态
try {
        // 同步调用执行器函数
        executor(resolve, reject)
    } catch (error) {
        //修改Promise对象的状态为失败
        reject(error)
    }

Promise对象状态只能修改一次

  • 由于状态只能改变一次,且只能由pendding状态变为其他,故要进行判断
function resolve(data) {
			//如果不是‘pendding’状态 ,不会进行状态的改变
        if (self.promiseState !== 'pendinng') return;
        //1.修改对象的状态 (promiseState)
        self.promiseState = 'fulfilled'
        //2.设置对象结果值 (promiseResult)
        self.promiseResult = data
    }

    function reject(data) {
        if (self.promiseState !== 'pendinng') return;
        //1.修改对象的状态 (promiseState)
        self.promiseState = 'rejected'
        //2.设置对象结果值 (promiseResult)
        self.promiseResult = data
    }

then方法执行回调

myPromise.prototype.then = function (onResolved, onRejected) {
    // 回调函数执行
    if (this.promiseState === 'fulfilled'){
        onResolved(this.promiseResult)
    }
    if (this.promiseState === 'rejected') {
        onRejected(this.promiseResult)
    }
}

异步任务then回调的执行

  • 若异步执行回调函数,then方法不会执行,由于异步,状态还未发生改变,便执行then方法
let p = new myPromise((resolve,reject)=>{
        setTimeout(() => {
             resolve('OK')
         }, 1000);
     })
  • 故还需要进行判断,真正调用回调函数的时机是在(resolve, reject)中,我们需要在then方法中保存回调函数,在Promise对象中声明一个属性保存成功和失败的回调函数
function myPromise(executor) {
    //为实例对象添加属性
    this.promiseState = 'pendinng'
    this.promiseResult = null
    this.callback = {}
  • 在then方法中判断,一旦promise 是pendding状态,将回调函数保存到该属性中
myPromise.prototype.then = function (onResolved, onRejected) {
    // 回调函数执行
    if (this.promiseState === 'fulfilled'){
        onResolved(this.promiseResult)
    }
    if (this.promiseState === 'rejected') {
        onRejected(this.promiseResult)
    }
    //判断pendding状态
    if (this.promiseState === 'pendinng'){
        this.callback = {
            onResolved,
            onRejected
        }
    }
}
  • 然后在promise对象中对应的(resolve, reject)函数里面调用
function resolve(data) {
        if (self.promiseState !== 'pendinng') return;
        //1.修改对象的状态 (promiseState)
        self.promiseState = 'fulfilled'
        //2.设置对象结果值 (promiseResult)
        self.promiseResult = data
        //判断当前是否存在回调函数
        if(self.callback.onResolved){
            self.callback.onResolved(data)
        }
    }

指定多个回调的实现

  • 上述方法修改回调函数会存在一个问题,若是后面新增的then方法会将之前的回调函数覆盖
		//弹窗会出现,而控制台输出没有 原因是弹窗回调函数覆盖了输出的回调函数
		p.then(value => {
            console.log(value);
        }, reason => {
            console.warn(reason);
        })
        p.then(value => {
            alert(value);
        }, reason => {
            alert(reason);
        })
  • 更改:用数组保存回调函数,在(resolve, reject)函数遍历执行
this.callbacks = []
------------.then-----------
if (this.promiseState === 'pendinng'){
        this.callbacks.push({
            onResolved,
            onRejected
        })
    }
-----------(resolve, reject)------------
		//判断当前是否存在回调函数
	     self.callbacks.forEach(item=>{
	         item.onResolved(data)
	     })

同步任务下修改状态then方法结果返回

  • 由于then方法的返回值是一个promise对象,由参数函数的状态及值决定
        const result = p.then(value => {
            console.log(value);
            //未return 所以值为undefined
        }, reason => {
            console.warn(reason);
        })
        console.log(result); // Promise:fufilled undefined
  • 首先then方法实现的是一个promise对象,然后考虑到回调函数返回的是promise对象还是值还是抛出错误
myPromise.prototype.then = function (onResolved, onRejected) {
    return new myPromise((resolve,reject)=>{
        // 回调函数执行
        if (this.promiseState === 'fulfilled') {
            try {
                let result = onResolved(this.promiseResult)
                if (result instanceof myPromise) {
                    // 如果是promise对象
                    result.then(v => {
                        resolve(v)
                    }, r => {
                        reject(r)
                    })
                } else {
                    // 只是一个值 状态就是成功
                    resolve(result)
                }
            } catch (error) {
                reject(error)
            }
        }
        ...reject
}

异步任务下修改状态then方法结果返回

  • 若是异步,由于状态仍然是pendding,进入到此时的then方法中,并没有调用resolve或者reject函数,因此返回的结果promise仍然是pendding状态
		//判断pendding状态
		const self = this
        //判断pendding状态
        if (this.promiseState === 'pendinng') {
            this.callbacks.push({
                onResolved: function () {
                    //这里要注意this的指向
                    try {
                        let result = onResolved(this.promiseResult)
                        if (result instanceof myPromise) {
                            // 如果是promise对象
                            result.then(v => {
                                resolve(v)
                            }, r => {
                                reject(r)
                            })
                        } else {
                            // 只是一个值 状态就是成功
                            resolve(result)
                        }
                    } catch (error) {
                        reject(error)
                    }
                },
                onRejected: function () {

                }

then方法的完善和优化

  • 重复率太高,进行封装
function callback(type) {
        try {
              let result = type(self.promiseResult)
              if (result instanceof myPromise) {
                  // 如果是promise对象
                  result.then(v => {
                      resolve(v)
                  }, r => {
                      reject(r)
                  })
              } else {
                  // 只是一个值 状态就是成功
                  resolve(result)
              }
          } catch (error) {
              reject(error)
          }
      }
-------------then return ---------------
// 回调函数执行
        if (this.promiseState === 'fulfilled') {
            callback(onResolved)
        }
        if (this.promiseState === 'rejected') {
            callback(onRejected)
        }

then方法回调的异步执行

  • 需要实现下述代码的异步执行 ,输出132
let p = new myPromise((resolve, reject) => {
            resolve('OK')
            console.log(111);
        })
        p.then(value => {
            console.log(222);
        })
        console.log(333);
  • 需要在then方法成功和失败的状态下,以及promise对象中的resolve和reject的回调函数数组,用定时器包裹
-----------------.then ------------------
// 回调函数执行
        if (this.promiseState === 'fulfilled') {
            setTimeout(() => {
                callback(onResolved)
            });
        }
//resolve函数
//判断当前是否存在回调函数
        setTimeout(() => {
            self.callbacks.forEach(item => {
                item.onResolved(data)
            })
        });

catch方法-异常穿透与值传递

p.catch(reason=>{
            console.warn(reason);
        })
  • 添加catch方法
myPromise.prototype.catch = function(onRejected){
    return this.then(undefined,onRejected)
}
  • 实现异常穿透和值传递,让then方法中的两个函数参数是可传可不传的
// 判断回调函参数
	if(typeof onResolved!== 'function'){
	        onResolved= value => value
	    }
    if(typeof onRejected !== 'function'){
        onRejected = reason=>{
            throw reason
        }
    }

promise函数上resolve方法的封装

  • 快速生成一个promise对象
const p = Promise.resolve('OK')
  • 添加resolve方法,该方法不是实例上的方法
myPromise.resolve = function(value){
    return new myPromise((resolve,reject)=>{
        if (value instanceof myPromise) {
            // 如果是promise对象
            value.then(v => {
                resolve(v)
            }, r => {
                reject(r)
            })
        } else {
            // 只是一个值 状态就是成功
            resolve(value)
        }
    })
}

promise函数上reject方法的封装

  • 状态永远是失败
myPromise.resolve = function (reason) {
    return new myPromise((resolve, reject) => {
        reject(reason)
    })
}

promise函数上all方法的封装

  • 返回promise对象,参数为promise组成的数组,结果为成功结果的数组,有一个失败就失败
myPromise.all = function (promises) {
    return new myPromise((resolve, reject) => {
        // 标记成功的次数
        let count = 0
        // 保存成功的结果
        let res = []

        for(let i = 0;i < promises.length;i++){
            promises[i].then(v=>{
                count++
                res[i] = v //不能用push 不能保证结果的顺序
                if(count === promises.length) resolve(res);
            },r=>{
                reject(r)
            })
        }
    })
}

promise函数上race方法的封装

  • 状态由最先改变的promise对象有关
myPromise.race = function (promises) {
    return new myPromise((resolve, reject) => {
        for (let i = 0; i < promises.length; i++) {
            promises[i].then(v => {
                resolve(v);
            }, r => {
                reject(r)
            })
        }
    })
}

class版本实现

class Promise {
 //构造方法
 constructor(executor) {
   //添加属性
   this.PromiseState = 'pending';
   this.PromiseResult = null;
   //声明属性
   this.callbacks = [];
   //保存实例对象的 this 的值
   //resolve 函数
   let resolve = (data) => {
     //判断状态
     if (this.PromiseState !== 'pending') return;
     //1. 修改对象的状态 (promiseState)
     this.PromiseState = 'fulfilled'; // resolved
     //2. 设置对象结果值 (promiseResult)
     this.PromiseResult = data;
     //调用成功的回调函数
     setTimeout(() => {
       this.callbacks.forEach(item => {
         item.onResolved(data);
       });
     });
   }
   //reject 函数
   let reject = (data) => {
     //判断状态
     if (this.PromiseState !== 'pending') return;
     //1. 修改对象的状态 (promiseState)
     this.PromiseState = 'rejected'; // 
     //2. 设置对象结果值 (promiseResult)
     this.PromiseResult = data;
     //执行失败的回调
     setTimeout(() => {
       this.callbacks.forEach(item => {
         item.onRejected(data);
       });
     });
   }
   try {
     //同步调用『执行器函数』
     executor(resolve, reject);
   } catch (e) {
     //修改 promise 对象状态为『失败』
     reject(e);
   }
 }

 //then 方法封装
 then(onResolved, onRejected) {
   //判断回调函数参数
   if (typeof onRejected !== 'function') {
     onRejected = reason => {
       throw reason;
     }
   }
   if (typeof onResolved !== 'function') {
     onResolved = value => value;
     //value => { return value};
   }
   return new Promise((resolve, reject) => {
     //封装函数
     let callback = (type) => {
       try {
         //获取回调函数的执行结果
         let result = type(this.PromiseResult);
         //判断
         if (result instanceof Promise) {
           //如果是 Promise 类型的对象
           result.then(v => {
             resolve(v);
           }, r => {
             reject(r);
           })
         } else {
           //结果的对象状态为『成功』
           resolve(result);
         }
       } catch (e) {
         reject(e);
       }
     }
     //调用回调函数  PromiseState
     if (this.PromiseState === 'fulfilled') {
       setTimeout(() => {
         callback(onResolved);
       });
     }
     if (this.PromiseState === 'rejected') {
       setTimeout(() => {
         callback(onRejected);
       });
     }
     //判断 pending 状态
     if (this.PromiseState === 'pending') {
       //保存回调函数
       this.callbacks.push({
         onResolved: function () {
           callback(onResolved);
         },
         onRejected: function () {
           callback(onRejected);
         }
       });
     }
   })
 }

 //catch 方法
 catch (onRejected) {
   return this.then(undefined, onRejected);
 }

 //添加 resolve 方法
 static resolve(value) {
   //返回promise对象
   return new Promise((resolve, reject) => {
     if (value instanceof Promise) {
       value.then(v => {
         resolve(v);
       }, r => {
         reject(r);
       })
     } else {
       //状态设置为成功
       resolve(value);
     }
   });
 }

 //添加 reject 方法
 static reject(reason) {
   return new Promise((resolve, reject) => {
     reject(reason);
   });
 }

 //添加 all 方法
 static all(promises) {
   //返回结果为promise对象
   return new Promise((resolve, reject) => {
     //声明变量
     let count = 0;
     let arr = [];
     //遍历
     for (let i = 0; i < promises.length; i++) {
       //
       promises[i].then(v => {
         //得知对象的状态是成功
         //每个promise对象 都成功
         count++;
         //将当前promise对象成功的结果 存入到数组中
         arr[i] = v;
         //判断
         if (count === promises.length) {
           //修改状态
           resolve(arr);
         }
       }, r => {
         reject(r);
       });
     }
   });
 }

 //添加 race 方法
 static race(promises) {
   return new Promise((resolve, reject) => {
     for (let i = 0; i < promises.length; i++) {
       promises[i].then(v => {
         //修改返回对象的状态为 『成功』
         resolve(v);
       }, r => {
         //修改返回对象的状态为 『失败』
         reject(r);
       })
     }
   });
 }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值