手写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嵌套的返回值。具体处理看上诉代码。

 

 

 

 

 

posted @ 2021-08-15 12:22  古墩古墩  Views(143)  Comments(0Edit  收藏  举报