promise原理就是这么简单

异步编程的几种形式:

回调函数形式:

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

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

发布订阅模式

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: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完成异步任务。bash

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对象,本文参考:async

  1. Promise A+规范
  2. Es6入门之promise对象
  3. Promise 源码
  4. 教你一步步实现promise
相关文章
相关标签/搜索