promise原理就是这么简单

异步编程的几种形式:

回调函数形式:

function f1(callback){
    callback();
}
function f2(callback){
    callback();
}
function f3(callback){
    callback();
}
f1(f2(f3))
复制代码

这种方式实现异步编程优点是思路清晰,以串行的思考方式进行编程,缺点是形成回调地狱,过多的回调嵌套使得代码变得难以理解拆分和维护。

发布订阅模式

let dep = {
  list: [],
  on: function (fn) {
    list.push(fn);
  },
  emit: function () {
    this.list.forEach(event => {
      typeof event === 'function' ? event() : null;
    })
  }
};
复制代码

上面就是简易版的发布订阅模式:发布者存在一个数组list用于登记订阅者即异步执行的函数,等到一定条件下执行emit,订阅的异步函数都会执行。这就好比发布者售楼中心的拥有一个登记册,里面登记需要买房的所有订阅者,有的订阅者登记的是电话通知,有的订阅者登记的邮件通知,等到楼盘信息变化时会主动给每个订阅者执行相应的操作(执行对应的函数)

promise

promise的核心原理其实就是发布订阅模式,通过两个队列来缓存成功的回调(onResolve)和失败的回调(onReject)。如果还不熟悉promise用法的朋友,请参考Es6入门之promise对象,下面来分析promise的特点。

promise的特点:
  1. new Promise时需要传递一个executor执行器,执行器会立刻执行
  2. 执行器中传递了两个参数:resolve成功的函数、reject失败的函数,他们调用时可以接受任何值的参数value
  3. promise状态只能从pending态转onfulfilled,onrejected到resolved或者rejected,然后执行相应缓存队列中的任务
  4. promise实例,每个实例都有一个then方法,这个方法传递两个参数,一个是成功回调onfulfilled,另一个是失败回调onrejected
  5. promise实例调用then时,如果状态resolved,会让onfulfilled执行并且把成功的内容当作参数传递到函数中
  6. promise中可以同一个实例then多次,如果状态是pengding 需要将函数存放起来 等待状态确定后 在依次将对应的函数执行 (发布订阅)
promise基础版实现

下面针对这些特点来实现promise:

new Promise时需要传递一个executor执行器,执行器会立刻执行;执行器中传递了两个参数:resolve成功的函数、reject失败的函数,他们调用时可以接受任何值的参数value
function Promise (executor){
    function resolve(value){}
    function reject(value){}
    try{
        executor(resolve,reject);
    }catch(e){
        reject(e);
    }
}
var promise = new Promise((resolve,reject)=>{
    console.log('start');
})
复制代码
promise状态只能从pending态转onfulfilled,onrejected到resolved或者rejected
function Promise (executor) {
  var self = this;//resolve和reject中的this指向不是promise实例,需要用self缓存
  self.state = 'padding';
  self.value = '';//缓存成功回调onfulfilled的参数
  self.reson = '';//缓存失败回调onrejected的参数
  self.onResolved = []; // 专门存放成功的回调onfulfilled的集合
  self.onRejected = []; // 专门存放失败的回调onrejected的集合
  function resolve (value) {
    if(self.state==='padding'){
      self.state==='resolved';
      self.value=value;
      self.onResolved.forEach(fn=>fn())
    }
  }
  function reject (reason) {
    self.state = 'rejected';
    self.value = reason;
    self.onRejected.forEach(fn=>fn())
  }
  try{
    executor(resolve,reject)
  }catch(e){
    reject(e)
  }
}
复制代码
promise实例,每个实例都有一个then方法,这个方法传递两个参数,一个是成功回调onfulfilled,另一个是失败回调onrejected;
promise实例调用then时,如果状态resolved,会让onfulfilled执行并且把成功的内容当作参数传递到函数中;
promise中可以同一个实例then多次,如果状态是pengding 需要将函数存放起来 等待状态确定后 在依次将对应的函数执行(发布订阅)
Promise.prototype.then=function (onfulfilled,onrejected) {
  var self=this;
  if(this.state==='resolved'){
    onfulfilled(self.value)
  }
  if(this.state==='rejected'){
    onrejected(self.value)
  }
  if(this.state==='padding'){
    this.onResolved.push(function () {
      onfulfilled(self.value)
    })
  }
}
复制代码
then方法的特点:

以上只是实现了promise的基本功能,但是还缺少then的链式调用,then函数参数onfulfilled,onrejected缺省处理,链式调用返回值多种情况的处理,下面分析then方法的特点:

  1. 因为promise状态确定后就是不能更改,所以每次promise执行then后都会返回一个新的promise而不是this,那么状态永远为resolve或jeject,将存在异步调用
  2. onfulfilled或onrejected是一个可选参数,需要做没有传递时的处理
  3. 如果then中onfulfilled或onrejected返回的是一个普通值的话会把这个结果传递下一次then中的成功回调
  4. 如果then中onfulfilled或onrejected出现异常,会走下一个then的失败回调,将err传递到失败回调中
  5. 如果失败后还可以成功,如果返回undefined,会把undefined传递给下一次
  6. 如果then方法返回的是一个promise,那么会等待这个promise执行完决定返回的是成功还是失败
promise优化版实现
因为promise状态确定后就是不能更改,所以每次promise执行then后都会返回一个新的promise而不是this,那么状态永远为resolve或jeject,将存在异步调用;onfulfilled或onrejected是一个可选参数,需要做没有传递时的处理
Promise.prototype.then=function (onfulfilled,onrejected) {
    onfulfilled = typeof onfulfilled == 'function' ? onfulfilled : val => val;//onfulfilled缺省处理
    onrejected = typeof onrejected === 'function' ? onrejected : err => {throw err;};//onrejected缺省处理
  var self=this,promise2=new Promise(function(resolve,reject){//返回一个promise
    if(this.state==='resolved'){
    try{
        onfulfilled(self.value);//里面会执行resolve    
    }catch(e){
        reject(e);
    }
  }
  if(this.state==='rejected'){
    try{
        onrejected(self.value);
    }catch(e){
        reject(e);
    }
  }
  if(this.state==='padding'){//将执行过程缓存
   self.onResolved.push(function () {
        try{
            onfulfilled(self.value);
        }catch(e){
           reject(e)
        }
    });
    self.onRejected.push(function () {
        try{
            onrejected(self.value);
        }catch(e){
            reject(e)
        }
    })
  }  
  })
  return promise2;
}
复制代码
如果then中onfulfilled或onrejected返回的是一个普通值的话会把这个结果传递下一次then中的成功回调;
如果then中onfulfilled或onrejected出现异常,会走下一个then的失败回调,将err传递到失败回调中;
如果失败后还可以成功,如果返回undefined,会把undefined传递给下一次;
如果then方法返回的是一个promise,那么会等待这个promise执行完决定返回的是成功还是失败,所以需要对onfulfilled或onrejected的返回值进行处理。
Promise.prototype.then=function (onfulfilled,onrejected) {
    onfulfilled = typeof onfulfilled == 'function' ? onfulfilled : val => val;
    onrejected = typeof onrejected === 'function' ? onrejected : err => {throw err;};
  var self=this,
    res=null,//用来缓存onfulfilled或onrejected的返回值
    promise2=new Promise(function(resolve,reject){
    if(this.state==='resolved'){
    try{
        res = onfulfilled(self.value);//得到onfulfilled的返回值
        resolvePromise(promise2,res,resolve,reject);//返回值的处理函数
    }catch(e){
        reject(e);
    }
  }
  if(this.state==='rejected'){
    try{
        res = onrejected(self.value);//得到onrejected的返回值
        resolvePromise(promise2,res,resolve,reject);
    }catch(e){
        reject(e);
    }
  }
  if(this.state==='padding'){
   self.onResolved.push(function () {
        try{
            res = onfulfilled(self.value);
            resolvePromise(promise2,res,resolve,reject);
        }catch(e){
           reject(e)
        }
    });
    self.onRejected.push(function () {
        try{
            res = onrejected(self.value);
            resolvePromise(promise2,res,resolve,reject);
        }catch(e){
            reject(e)
        }
    })
  }  
  })
  return promise2;
}
function resolvePromise(promise,res,resolve,reject) {
  if(promise===res){//防止循环引用
    return reject(new TypeError('循环引用'))
  }
  let called;//防止重复执行
  if(res!==null&&(typeof res==='function'||typeof res ==='object')){
    try {//防止promise执行报错
      let then=res.then;//判断是否promise就判断是否存在then方法
      if(typeof then ==='function'){//如果返回的是promise,只需要在返回的promise的then方法中下一步需要执行的函数
        then.call(res,(res2)=>{
          if (called) return;
          called = true;
          resolvePromise(promise,res2,resolve,reject);//如果是promise继续递归执行,直到不是promise,依次执行外层的resolve,让promise状态改变
        },)
      }else{//如果不是promise,有可能是undefine、onfulfilled或onrejected的返回的普通值,就直接将这个值返回,将外层的promise状态改变
        if (called) return;
        called = true;
        resolve(then)
      }
    }catch(e){
      if (called) return;
      called = true;
      reject(e)
    }
  }else{
    resolve(res)
  }
};
复制代码
promise.then属于异步微任务,then中的方法,必须等到所有的同步任务执行完才执行,宏任务和微任务可以查看EventLoop其实如此简单
console.log(1);
var promise=new Promise(function(resolve,reject){
    resolve('a');
})
promise.then(function(value){
    console.log(value)
})
console.log(2);
// 1 2 'a'
复制代码
//由于promise有内部的机制实现微任务,所以这里使用setTimeout代替
Promise.prototype.then=function (onfulfilled,onrejected) {
    onfulfilled = typeof onfulfilled == 'function' ? onfulfilled : val => val;
    onrejected = typeof onrejected === 'function' ? onrejected : err => {throw err;};
  var self=this,
    res=null,
    promise2=new Promise(function(resolve,reject){
    if(this.state==='resolved'){
        setTimeout(()=>{
            try{
                res = onfulfilled(self.value);
                resolvePromise(promise2,res,resolve,reject);
            }catch(e){
                reject(e);
            }
        })
    }
  if(this.state==='rejected'){
        setTimeout(()=>{
            try{
                res = onrejected(self.value);
                resolvePromise(promise2,res,resolve,reject);
            }catch(e){
                reject(e);
            }  
        })
    }
  if(this.state==='padding'){
    self.onResolved.push(function () {
        setTimeout(()=>{
            try{
                res = onfulfilled(self.value);
                resolvePromise(promise2,res,resolve,reject);
            }catch(e){
                reject(e);
            }
        })
    });
    self.onRejected.push(function () {
        setTimeout(()=>{
            try{
                res = onrejected(self.value);
                resolvePromise(promise2,res,resolve,reject);
            }catch(e){
                reject(e);
            }  
        })
    })
  }  
  })
  return promise2;
}
复制代码
promise.catch会捕获到没有捕获的异常;
Promise.resolve会返回一个状态位rsolved的promise;
Promise.reject会返回一个状态位rsolved的promise;
Promise.all会在所有的promise resolved后执行回调,Promise.race只要有一个promise resolved就执行回调。
promise.catch将所有的错误在promise实例的下一个then中返回
Promise.prototype.catch = function (onrejected) {
  return this.then(null, onrejected)
};
复制代码
Promise.reject和Promise.reject
Promise.reject = function (reason) {
  return new Promise((resolve, reject) => {
    reject(reason)
  })
};
Promise.resolve = function (value) {
  return new Promise((resolve, reject) => {
    resolve(value);
  })
};
复制代码
Promise.all和Promise.race
//在每个promise的回调中添加一个判断函数processData(就是在当前的promise.then中添加),每个promise状态改变后让index++,直到和promises的个数相等就执行回调
Promise.all=function (promises) {
  return new Promise((resolve,reject)=>{
    let results=[],i=0;
    for(let i=0;i<promises.length;i++){
      let p=promises[i];
      p.then((data)=>{
        processData(i,data)
      },reject)
    }
    function processData (index,data) {
      results[index]=data;
      if(++i==promises.length){
        resolve(results)
      }
    }
  })
};
//在每个promise的回调中添加一个resolve(就是在当前的promise.then中添加),有一个状态改变,就让race的状态改变
Promise.race=function (promises) {
  return new promises((resolve,reject)=>{
    for(let i=0;i<promises.length;i++){
      let p=promises[i];
      p.then(resolve,reject)
    }
  })
};
复制代码

generator + co

Generator函数可以通过yield暂停执行和next恢复执行,所以可以封装一个函数来自动执行next函数而使Generator完成异步任务。

let fs = require('mz/fs');
function * read() {
  let age = yield fs.readFile('./name.txt','utf8');
  let adress = yield fs.readFile(age,'utf8');
  let r = yield fs.readFile(adress,'utf8');
  return r;
}
function co(it) {//it为一个generator对象
//返回一个promise并且执行generator对象的next
return new Promise((resolve,reject)=>{
    function next(data) {
        //获取前一个异步函数的返回值,其必须为promise
        let { value, done } = it.next(data);  
            if(!done){
            //返回promise的then方法中添加generator的next
            //前一个异步函数执行成功会使返回的promise成resolved
            //然后执行generator的next,递归依次类推
            value.then(data=>{  
                next(data)
            }, reject);
        }else{
            resolve(value);
        }
    }
        next();
  })
}
co(read()).then(data=>{
  console.log(data);
},err=>{
  console.log(err);
});
复制代码

async和awit

async+awit等于generator+co,而co中实现generator自动化是基于Promise,所以awit会使用new Promise形式。

结语

如果以上有任何错误之处,希望提出并请指正,如果对promise使用还不清楚的朋友,请参考Es6入门之promise对象,本文参考:

  1. Promise A+规范
  2. Es6入门之promise对象
  3. Promise 源码
  4. 教你一步步实现promise
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值