16年时在公司分享过一次promise,犹记得当时是第一次分享,还蛮紧张的,当时分享的主要是promise的使用和基本原理,后来又给无线部门同窗分享了一次。
如今回顾想一想,其实讲的不是很完美,由于我当时的实现方式相似于简化版q库的实现,考虑的也不全面,也没有彻底遵循promise/a+规范。通过这么长一段时间的学习和积累,阐述一下本身新的理解。vue
在没有promise之前,多个有依赖的异步操做通常写出来会出现嵌套,所谓的回调地域,这种写法在须要协做的项目中不方便维护,异步操做也不能直接捕获异常,须要回调中进行处理,缺点挺多的,而后就开始漫长的优化,出现了q, bluebird,jq中的defer等这些库,后来ES6标准实现了Promise,可是其链式写法仍是不美观,为了代码更优雅,能够视觉上同步命令式的书写代码有了TJ大神的co再结合generator彷佛完美了,可是为了优雅还要额外引入co库,成本有点大,后来ES7标准干脆直接实现了,就是所谓的async和await语法糖node
如今开始切入正题,什么是Promise呢? 简而言之promise表明承诺,专业术语就是表明一个异步操做的最终结果。
代码层面来看的话Promise是一个类,能够用来建立实例,每一个实例内部封装一些方法,且维护了一些状态和值,经过使用这些状态、值和方法来将现实流程中的承诺具体代码化表示。ios
promise主要提供了then,catch,all,race,resolve,reject这几个方法,关于这几个方法怎么使用不在赘述,由于占据文章篇幅长,且不少其它blog重复描述过。推荐阮一峰es6入门中相关api用法解释,详细且全面。
关于具体应用的话,因为在工做中项目基于vue技术栈,因此结合axios时会使用到promise来操做异步,还有就是m站基于pwa,其中Service worker声明周期事件处理中会涉及promise,还有一些就是平时写node工具的时候会用到,用promise封装异步api操做回调,从而将异步api回调逻辑直接放到then方法中进行处理。git
基于Promise/a+规范实现的代码能互相统一,虽然代码形式会有不一样,但原理都差很少。
首先Promise构造函数中须要有一些状态和方法,由于执行实例then逻辑的时候须要这些维护好的状态和值,其中着重提醒的就是promise的状态机是单向的,且状态单向不可逆。
状态转变只能是 pending -> fulfilled 或者 pending -> rejected。es6
//构造函数初始化逻辑 let that = this; //缓存this //默认状态为pending that.status = 'pending'; //此变量里放着此promise的结果 that.value = undefined; //存放的着全部成功的回调函数 that.onResolvedCallbacks = []; //存放着全部的失败的回调函数 that.onRejectedCallbacks = [];
其中内部resolve和reject逻辑以下,更改状态机状态,触发承诺逻辑执行github
function resolve(value) { //更改状态 执行then注册的成功回调逻辑 if (that.status == 'pending') { //解决resolve 新Promise这种状况 if(value!=null &&value.then&&typeof value.then == 'function'){ return value.then(resolve,reject); } that.status = 'fulfilled'; that.value = value; that.onResolvedCallbacks.forEach(item=>item(that.value)); } } function reject(reason) { //更改状态 执行then注册的失败回调逻辑或者catch中注册的失败逻辑 if (that.status == 'pending') { that.status = 'rejected'; that.value = reason; that.onRejectedCallbacks.forEach(item=>item(that.value)); } }
上面已经介绍了大体初始化逻辑了,下面着重介绍使用频率最高的then方法,简洁版实现以下所示axios
PPromise.prototype.then = function (onFulfilled, onReject) { //成功和失败的逻辑没有传递 会进行值的穿透 传递给下一个then方法 onFulfilled = isFunction(onFulfilled) ?onFulfilled:val =>val; onReject = isFunction(onReject) ?onReject:reason => {throw reason;} let self = this,promise2; switch (self.status){ case 'fulfilled': promise2 = new Promise((resolve,reject) =>{ let x = onFulfilled(self.value); if(x instanceof Promise){ //递归执行then逻辑 直到内部then执行,外部promise2被resolve x.then(resolve,reject) }else{ resolve(x); } }); break case 'rejected': promise2 = new Promise((resolve,reject) =>{ let x = onReject(self.value); if(x instanceof Promise){ x.then(resolve,reject) }else{ resolve(x); } }) break case 'pending': promise2 = new Promise((resolve,reject) =>{ self.onResolvedCallbacks.push(function(){ let x = onFulfilled(self.value); if(x instanceof Promise){ x.then(resolve,reject) }else{ resolve(x); } }); self.onRejectedCallbacks.push(function(){ let x = onReject(self.value); if(x instanceof Promise){ x.then(resolve,reject) }else{ resolve(x); } }); }); } return promise2; }
all方法实现segmentfault
function sentry(times,cb){ let result = [],count=0; return function(i,data){ result[i] = data; if(++count==times){ cb(result); } } } Promise.all = function(promises){ return new Promise((resolve,reject) => { //利用闭包机制,目的是为了判断promises是否都执行完 let done = sentry(promises.length,resolve); for(let i=0;i<promises.length;i++){ promises[i].then(data =>{ done(i,data); },reject); } }); }
resolve实现api
Promise.resolve = function(value){ return new Promise(function(resolve){ resolve(value); }); }
race实现promise
Promise.race = function(promises){ return new Promise((resolve,reject) =>{ for(let i=0;i<promises.length;i++){ promises[i].then(resolve,reject); } }); }
本身实现的promise源码
异步操做通过promisify转化成promise,在结合async实现优雅的写法
let Promise = require('bluebird'); let readFile = Promise.promisify(require('fs').readFile); async function read() { let a = await readFile('./1.txt','utf8'); let b = await readFile('./2.txt','utf8'); let c = await readFile('./3.txt','utf8'); console.log(c); return 'ok'; } read().then(data => { console.log(data); });
任何事物都不是一蹴而就的,都有一个发展过程才逐步变得完美,将本身的学习坐下记录,并加一些我的思考,若是对于本文有任何疑问或错误,欢迎斧正交流。
参考连接
https://promisesaplus.com/
https://segmentfault.com/a/11...