这种方式实现异步编程优点是思路清晰,以串行的思考方式进行编程,缺点是形成回调地狱,过多的回调嵌套使得代码变得难以理解拆分和维护。
上面就是简易版的发布订阅模式:发布者存在一个数组list用于登记订阅者即异步执行的函数,等到一定条件下执行emit,订阅的异步函数都会执行。这就好比发布者售楼中心的拥有一个登记册,里面登记需要买房的所有订阅者,有的订阅者登记的是电话通知,有的订阅者登记的邮件通知,等到楼盘信息变化时会主动给每个订阅者执行相应的操作(执行对应的函数)
promise的核心原理其实就是发布订阅模式,通过两个队列来缓存成功的回调(onResolve)和失败的回调(onReject)。如果还不熟悉promise用法的朋友,请参考Es6入门之promise对象,下面来分析promise的特点。
promise的特点:
new Promise时需要传递一个executor执行器,执行器会立刻执行执行器中传递了两个参数:resolve成功的函数、reject失败的函数,他们调用时可以接受任何值的参数valuepromise状态只能从pending态转onfulfilled,onrejected到resolved或者rejected,然后执行相应缓存队列中的任务promise实例,每个实例都有一个then方法,这个方法传递两个参数,一个是成功回调onfulfilled,另一个是失败回调onrejectedpromise实例调用then时,如果状态resolved,会让onfulfilled执行并且把成功的内容当作参数传递到函数中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方法的特点:
因为promise状态确定后就是不能更改,所以每次promise执行then后都会返回一个新的promise而不是this,那么状态永远为resolve或jeject,将存在异步调用onfulfilled或onrejected是一个可选参数,需要做没有传递时的处理如果then中onfulfilled或onrejected返回的是一个普通值的话会把这个结果传递下一次then中的成功回调如果then中onfulfilled或onrejected出现异常,会走下一个then的失败回调,将err传递到失败回调中如果失败后还可以成功,如果返回undefined,会把undefined传递给下一次如果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函数可以通过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等于generator+co,而co中实现generator自动化是基于Promise,所以awit会使用new Promise形式。
如果以上有任何错误之处,希望提出并请指正,如果对promise使用还不清楚的朋友,请参考Es6入门之promise对象,本文参考:
Promise A+规范Es6入门之promise对象Promise 源码教你一步步实现promise作者:梦想攻城狮 链接:https://juejin.im/post/5b9645c75188255c463669e9 来源:掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。