这篇文章内容主要来自一篇stack Overflow高票答案javascript
声明:此Promise的实现仅仅是为了加深本人对其的理解,和A+规范有些出入,可是的确是目前看过全部promise代码中最漂亮,思路比较清晰的一个。
文章不会特地帮助读者复习Promise基本操做。java
Promise其实本质上就是一个状态机,因此首先咱们描述一个静态的状态机,就像下边这样git
var PENDING = 0; var FULFILLED = 1; var REJECTED = 2; function Promise() { // 存储的状态是上边的三个:执行中,已完成,已拒绝 var state = PENDING; // 存储异步结果或者异步错误消息 var value = null; // 负责处理中途加入的处理函数 var handlers = []; }
完成了基本的状态机定义,接下来的问题就是完成“状态改变”这个动做的实现:github
var PENDING = 0; var FULFILLED = 1; var REJECTED = 2; function Promise() { // 存储三个状态 var state = PENDING; // 一旦出现状态的改变,异步结果就会被存到这个地方 var value = null; // 存储成功或者失败的handler var handlers = []; //状态转移到成功 function fulfill(result) { state = FULFILLED; value = result; } //状态转移到失败 function reject(error) { state = REJECTED; value = error; } }
到目前为止,咱们给出了两个很纯粹的变化动做,在开发的过程当中这两个动做会很很差用,因此咱们在这两个动做的基础上构建一个高层次的动做(其实就是加点判断而后封装一层),就像下边这儿,名字就叫作resolve,可是注意和咱们正常使用promise调用的那个resolve并不同,不要搞混:promise
var PENDING = 0; var FULFILLED = 1; var REJECTED = 2; function Promise() { var state = PENDING; var value = null; var handlers = []; function fulfill(result) { state = FULFILLED; value = result; } function reject(error) { state = REJECTED; value = error; } //这里暂时缺乏两个重要函数getThen和doResolve这两个函数,稍后会说道 function resolve(result) { try { var then = getThen(result); //判断then是否是一个Promise对象 if (then) { doResolve(then.bind(result), resolve, reject) return } fulfill(result); } catch (e) { reject(e); } } }
是的,咱们的用到了两个辅助函数getThen和doResolve,如今给出实现:异步
/** * 这里会判断value的类型,咱们只要promise.then这个函数,其余的通通返回null * * @param {Promise|Any} value * @return {Function|Null} */ function getThen(value) { var t = typeof value; if (value && (t === 'object' || t === 'function')) { var then = value.then; if (typeof then === 'function') { return then; } } return null; } /** * 这个函数的主要做用就是串主逻辑,完成“变化状态”这个动做 * * @param {Function} fn A resolver function that may not be trusted * @param {Function} onFulfilled * @param {Function} onRejected */ function doResolve(fn, onFulfilled, onRejected) { //done的做用是让onFulfilled或者onRejected仅仅被调用一次,状态机状态一旦改变无法回头 var done = false; try { //在咱们正常使用Promise的时候调的resolve,其实用的就是这里fn注入函数而后调用 fn(function (value) { if (done) return done = true **onFulfilled(value)** }, function (reason) { if (done) return done = true onRejected(reason) }) } catch (ex) { if (done) return done = true onRejected(ex) } }
好了,一个完整的状态机已经完成,咱们完成了一个基本的状态变化逻辑,接下来要作的就是一步一步的朝promise标准进发,这个promise缺乏什么呢,暂时缺的就是初始的动做啦(new promise(func)对象一旦被初始化内部代码当即执行),因此咱们加上初始动做的开启async
var PENDING = 0; var FULFILLED = 1; var REJECTED = 2; function Promise(fn) { var state = PENDING; var value = null; var handlers = []; function fulfill(result) { state = FULFILLED; value = result; } function reject(error) { state = REJECTED; value = error; } function resolve(result) { try { var then = getThen(result); if (then) { doResolve(then.bind(result), resolve, reject) return } fulfill(result); } catch (e) { reject(e); } } //开启任务的执行,因此我说doResolve其实才是“主线任务”的引子,而fn其实就是你写的代码 doResolve(fn, resolve, reject); }
咱们实现了状态机,可是目前的问题是咱们只能眼睁睁的看着代码的流动直到一个Promise结束为止,即无法添加也无法获取结果,这就有很大的局限性了,因此咱们要使用then方法来串联Promise,用done方法来完成结果的收集,首先实现done方法,由于then其实说白了就是收集上边的结果--完成本身的逻辑--把结果传递给下一个Promise,作的事情是done的超集。函数
var PENDING = 0; var FULFILLED = 1; var REJECTED = 2; function Promise(fn) { var state = PENDING; var value = null; var handlers = []; function fulfill(result) { state = FULFILLED; value = result; //专门封装一个handle函数处理后续逻辑,在下面有this.handle(handler)方法 handlers.forEach(handle); //在状态变成已处理而且以前加入的handler都被处理完毕的状况下再加入handler就会报错而且没有卵用 handlers = null; } function reject(error) { state = REJECTED; value = error; handlers.forEach(handle); handlers = null; } function resolve(result) { try { var then = getThen(result); if (then) { doResolve(then.bind(result), resolve, reject) return } fulfill(result); } catch (e) { reject(e); } } function handle(handler) { if (state === PENDING) { handlers.push(handler); } else { if (state === FULFILLED && typeof handler.onFulfilled === 'function') { handler.onFulfilled(value); } if (state === REJECTED && typeof handler.onRejected === 'function') { handler.onRejected(value); } } } //注意看下面done方法的实现,里边只有一个异步方法,换句话说就是会当即返回不会产生阻塞,咱们以后会在then当中调用done方法,这里的onFulfilled, onRejected就是用户写的处理函数,promise异步的特性就是这样来的。 this.done = function (onFulfilled, onRejected) { // ensure we are always asynchronous setTimeout(function () { handle({ onFulfilled: onFulfilled, onRejected: onRejected }); }, 0); } doResolve(fn, resolve, reject); }
最后,咱们来实现Promise.then,完成状态机的串联:性能
//这段代码有点绕,主要须要完成的工做其实就是,判断上一个Promise是否完成,而后执行用户的then里边的回调代码,并最终返回一个新的Promise,而后依次循环。。。 this.then = function (onFulfilled, onRejected) { //开启then以后就会返回一个新的promise,可是这个时候咱们还可能有上一个Promise的任务没有完成,因此先把上边一个promise对象的this指向保存下来 var self = this; //返回一个新包装Promise,这和咱们普通的在外边写new Promise是一个道理 return new Promise(function (resolve, reject) { //done的代码一样是当即返回,而后异步执行的 return self.done(function (result) { if (typeof onFulfilled === 'function') { try { return resolve(onFulfilled(result)); } catch (ex) { return reject(ex); } } else { return resolve(result); } }, function (error) { if (typeof onRejected === 'function') { try { return resolve(onRejected(error)); } catch (ex) { return reject(ex); } } else { return reject(error); } }); }); }
Over
更多参考请看下面:
简单的实现Promsie
高性能实现Promise,以及专门的wikithis