zoukankan      html  css  js  c++  java
  • 手写promise

    现代浏览器支持已经支持了promise,下面我用Cpromise类来重新写一个promise,探索一下promise实现的原理:

    直接上代码:

    /*
      Cpromise:构造函数
      excutor:内部同步执行函数  (resolve,reject) => {}
    */
    
    function Cpromise (excutor){
      this.state = 'pendding';//promise状态
      this.value = undefined;//正产返回值
      this.reason = undefined;//异常返回值
      this.resolveCallbacks = [];//正常状态回调队列
      this.rejectedCallbacks = [];//异常状态回调队列
    
      let resolve = value => {//正常执行函数
        // console.log(this.state,"resolve函数执行");
        if(this.state === 'pendding'){
          this.state = 'fulfilled';//promise状态变为正常状态
          this.value = value;//拿到正常返回值
          this.resolveCallbacks.forEach( fn => fn());//执行正常回调队列中的方法
        }
      };
    
      let reject = reason =>{//异常执行函数
        // console.log(this.state,"reject函数执行");
        if(this.state === 'pendding'){
          this.state = "rejected";//promise状态变为异常
          this.reason = reason;//拿到异常返回值
          this.rejectedCallbacks.forEach( fn => fn() );//执行异常回调队列里的方法
        }
      }
    
      try{
        // console.log("开始执行excutor函数");
        excutor(resolve,reject);//同步执行函数
      }catch(err){
        reject(err);
      }
    }
    
    Cpromise.prototype.then = function(onFulfilled,onRejected){
      // promise的then方法返回一个promise对象
      // console.log("执行then方法");
      onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;//设置then方法的默认正常回调
      onRejected = typeof onRejected === 'function' ? onRejected : err => {throw err};//设置then方法的默认异常回调
      let cpromise2 = new Cpromise((resolve,reject) => {
        if(this.state === 'fulfilled'){//then方法执行时,promise返回正常值时,直接执行then的正常回调
          // console.log("onFulfilled方法执行");
          setTimeout(() => {
            try {
              let x = onFulfilled(this.value);//执行then中的正常回调
              resolvePromise(cpromise2,x,resolve,reject);//执行resolve
            } catch (e) {
              reject(e)
            }
          },0)
        }
    
        if(this.state === 'rejected'){//then方法执行时,promise返回异常值时,直接执行then的异常回调
          // console.log("onRejected方法执行");
          setTimeout(() => {
            try {
              let x = onRejected(this.reason);//执行then中的异常回调
              resolvePromise(cpromise2,x,resolve,reject);//执行resolve
            } catch (e) {
              reject(e)
            }
          },0)
        }
    
        if(this.state === 'pendding'){//then方法执行时,同步函数体中的resolve或reject还没执行时,把then内的正常回调和异常回调放到各自的队列中,等待执行
          // console.log("向正常|异常回调队列添加回调");
          this.resolveCallbacks.push(() => {
            setTimeout(() => {
              try {
                let x = onFulfilled(this.value);//执行then中的正常回调
                resolvePromise(cpromise2,x,resolve,reject);//执行resolve
              } catch (e) {
                reject(e);
              }
            },0)
          });
          this.rejectedCallbacks.push(() => {
            setTimeout(() => {
              try {
                let x = onRejected(this.reason);//执行then中的异常回调
                resolvePromise(cpromise2,x,resolve,reject);//执行resolve
              } catch (e) {
                reject(e);
              }
            },0)
          })
        }
      });
      return cpromise2;
    }
    
    function resolvePromise(promise2,x,resolve,reject){//把正常|异常值放到 then方法返回出去的promise的返回值中
      if( x === promise2 ){
        return reject(new TypeError('Chaining cycle detected for promise'));
      }
      let called;
      if(x != null && (typeof x === 'object' || typeof x === 'function')){
        try {
          let then = x.then;
          if(typeof then === 'function'){//如果x是promise对象 就采用x这个promise对象的结果
            then.call(x,y => {
              if(called) return;
              called = true;
              resolvePromise(promise2, y, resolve, reject);//递归一下 y有可能还是promise对象   then方法内的promise对象都返回结果后,将结果返回给最外层的then的promise对象,然后返回(resolve|reject)出去
            },err => {
              if(called) return;
              called = true;
              reject(err);
            })
          }else{//如果不是promise 返回x
            resolve(x);
          }
        } catch (e) {
          if(called)return;
          called = true;
          reject(e); 
        }
      }else{//如果不是函数  返回 x
        resolve(x);
      }
    }
    // catch方法 then方法的语法糖
    Cpromise.prototype.catch = function(callback){
      return this.then(null,callback);
    }
    // resolve方法
    Cpromise.resolve = function(val){
      return new Cpromise((resolve,reject) => {
        resolve(val);
      })
    }
    // reject方法
    Cpromise.reject = function(val){
      return new Cpromise((resolve,reject) => {
        reject(val);
      })
    }
    
    // race方法
    Cpromise.race = function(promises){
      return new Cpromise((resolve,reject) => {
        for(let i = 0;i < promises.length;i++){
          promises[i].then(resolve,reject);//谁先执行完,就返回谁
        }
      })
    }
    
    // all方法
    Cpromise.all = function(promises){
      let arr = [];
      let i = 0;
      function processData(index,data,resolve){
        arr[index] = data;
        i++;
        if(i === promises.length){
          resolve(arr);
        }
      }
      return new Cpromise((resolve,reject) => {
        for(let i = 0;i < promises.length;i++){
          promises[i].then(data => {
            processData(i,data,resolve);
          },reject);
        }
      })
    }
    
    // 测试
    let p = new Cpromise((resolve,reject) => {
      let random = Math.floor(Math.random()*10);
      if(random > 5){
        resolve(random)
      }else{
        reject(random)
      }
    })
    p.then(data => {
      console.log(data,"resolve");
    }).catch(err => {
      console.log(err,"catch");
    })
    
    
    let p1 = new Cpromise((resolve,reject) => {
      setTimeout(() => {
        resolve(1000);
      },1000)
    })
    
    let p2 = new Cpromise((resolve,reject) => {
      setTimeout(() => {
        resolve(2000);
      },2000)
    })
    
    let pAll = Cpromise.all([p1,p2]).then(result => {
      console.log(result,"all");
    })
    
    let pRace = Cpromise.race([p1,p2]).then(result => {
      console.log(result,"race");
    })
    
    let pResolve =  Cpromise.resolve("resolve");
    pResolve.then(data => {
      console.log(data,"resolve");
    })
    
    let pReject = Cpromise.reject("reject");
    pReject.then(data => {
      console.log(data);
    },err => {
      console.log(err,"reject");
    })

    测试了一下,可以正常使用,

    说以下自己的大致理解:

    promise,主要把异步函数变成同步执行,避免了回调地狱

    原理其实还是用了回调函数,

    promise类内部有 

    状态变量 state  3个状态:pendding(正在执行)、fulfilled(正常返回)、rejected(异常返回)

    正常返回值变量:value

    异常返回值:reason

    正常返回回调 resolve

    异常返回回调 reject

    正常回调队列 resolveCallbacks

    异常回调队列 rejectCallbacks

    promise接收一个同步执行函数参数 excutor,实例化时执行此函数,执行时会把内部的resolve和reject函数作为参数传到excutor内;

    当excutor函数执行,状态冲pendding--->fulfilled 或 pendding --->rejected 时,分别执行 resolve和reject,从而将返回值传到then方法内

    函数执行顺序excutor、then

    当excutor内部不是异步函数时,then方法执行时,promise的状态已经变成了fullfilled或rejected,then方法就会直接执行then方法的正常回调或异常回调

    如果excutor是异步函数,then方法执行时,promise状态是pendding状态,这时,then方法会把then的两个回调分别放到promise内部的正常回调队列和异常回调队列中,等待excutor内部resolve或reject的执行,这两个方法会做如下事情:将状态改成成功或失败状态,将正常返回值赋值给value变量,或者把异常原因返回给reason,然后,执行对应队列中的方法。

    另外.then方法是可以链式调用的,需要then返回的是一个promise对象,假如then里的两个回调参数也是返回的promise对象,这里就需要做一些处理

    then方法会把then回调函数执行后得到的值,传给then本身的promise作为返回值,如果then内部是promise则,需要把回调函数promise的返回值传给then本身的promise的返回值,这样才是正常的。

    所以有一个resolvePromise函数,这里判断then内的回调是不是promise对象,如果是,则拿到then回到函数promise的返回值后再通过then本身的promise的resolve将值返回出去,如果then的回调不是promise对象,则直接把回调函数的返回值或一个基础值作为返回值传给then本身的promise。总结一下,then本身的promise要从回调内拿到返回值,二者个回调有可能是一个函数的返回值,也有可能是一个promise对象的返回值,也有可能是多个promise嵌套的返回值。具体处理看上诉代码。

  • 相关阅读:
    Jupyter notebook添加Anaconda中的虚拟环境
    Django踩坑之在Django中创建项目时ImportError: No module named django.core
    Django踩坑之ExtendsNode: extends 'base/base.html'> must be the first tag in the template.
    git 中文文件名乱码
    Django开发过程中遇到的问题和解决方案
    Advanced pandas
    Pycomcad中的过滤机制及访问引用块内对象简述
    头大的一篇日志 细节总结 唐诗三百首
    UIBarItem 的设置
    MJExtension json快速解析
  • 原文地址:https://www.cnblogs.com/fqh123/p/15143088.html
Copyright © 2011-2022 走看看