解读promise的模拟实现

create on in javascript with 0 comment and 375 view

promise是解决异步编程的一种方案,可避免回调地狱问题.

一个简单的例子: 1s过后控制台打印1

let promise = new Promise((resolve, reject) => { setTimeout(() => { resolve(1); },1000); }); promise.then((value)=>{ console.log('after 1s, num is '+ value); // 1 });

最近看到一些解读promise文章,我也挺好奇promise是怎么实现的,所以,就开始对promise的实现也解读了一番,算是对其有一个基础的认识,promise模拟实现.

相关概念

promise状态
每个promise都有状态,状态主要分为3种
1. pending(等待执行)
2. fulfilled(已执行)
3. reject(拒绝)

不同情况会触发不同的状态.
执行resolve成功: pending -> fulfilled
执行reject或执行代码发生异常: pending -> reject.

promise回调
promise对象的then方法中,有success和fail两个回调函数参数,当promise状态改变后,执行对应的回调。

promise.then((value)=>{ // fulfilled code... }, (err)=>{ // reject code... }).then(...);
  • defferred执行列表
    每个promise都有自己的延迟执行列表,可能是0个,也可能是1个或者多个,每个defferred对象由三个属性组成:
    1. defferred.promise (临时创建的promise)
    2. defferred.onfulfilled (状态变为fulfilled时的回调)
    3. defferred.onreject (状态变为reject的回调)

当promise从pending状态转化为其它状态后,这些延迟执行列表会被依次执行.例如:

var initPromise = new Promise(function(resolve, reject){ resolve(1) }) // defferend1 initPromise.then(function(data){ console.log("it's success1!") },function(err){ console.log("it's err1") }) // defferend2 initPromise.then(function(data){ console.log("it's success2!") },function(err){ console.log("it's err2") })
// 执行结果
it's success1!
it's success2!

initPromise调用then后,就会将defferrend1和defferend2加入到initPromise的defferend列表中。当resolve被执行后,会执行defferend中成功的回调,若被reject,则执行失败的回调。

源码分析

现在先写一段简单的promise代码,然后逐步分析对应源码执行情况.

var pro = new Promise(function(resolve, reject){ console.log('callback...'); resolve(1); }); pro.then(function(value){ console.log('one:'+value); return value+1; }, function (value) { console.log('reject:' + value); }) .then(function(value){ console.log('two:'+value); return value+1; }) .then(function(value){ console.log('last:'+value); })

源码结构图:
promise源码结构.png

这里先将源代码的解释列出来.

'use strict'; var asap = require('asap/raw'); function noop() {} // States: // // 0 - pending // 1 - fulfilled with _value // 2 - rejected with _value // 3 - adopted the state of another promise, _value // to avoid using try/catch inside critical functions, we // extract them to here. var LAST_ERROR = null; var IS_ERROR = {}; function getThen(obj) { try { return obj.then; } catch (ex) { LAST_ERROR = ex; return IS_ERROR; } } function tryCallOne(fn, a) { try { return fn(a); } catch (ex) { LAST_ERROR = ex; return IS_ERROR; } } function tryCallTwo(fn, a, b) { try { fn(a, b); } catch (ex) { LAST_ERROR = ex; return IS_ERROR; } } module.exports = Promise; function Promise(fn) { if (typeof this !== 'object') { throw new TypeError('Promises must be constructed via new'); } if (typeof fn !== 'function') { throw new TypeError('Promise constructor\'s argument is not a function'); } this._deferredState = 0; // defer的数量 0,1,2(代表2个及以上) this._state = 0; // 0 表示pending this._value = null; this._deferreds = null; // 待执行的回调 if (fn === noop) return; doResolve(fn, this); } Promise._onHandle = null; Promise._onReject = null; Promise._noop = noop; Promise.prototype.then = function(onFulfilled, onRejected) { if (this.constructor !== Promise) { return safeThen(this, onFulfilled, onRejected); // 确保this.constructor === Promise } var res = new Promise(noop); // 创建空回调的promise handle(this, new Handler(onFulfilled, onRejected, res)); return res; }; function safeThen(self, onFulfilled, onRejected) { return new self.constructor(function (resolve, reject) { var res = new Promise(noop); res.then(resolve, reject);// ? handle(self, new Handler(onFulfilled, onRejected, res)); }); } function handle(self, deferred) { // 处理deferred while (self._state === 3) { // 若当前promise为其它状态,通过resolve函数可知,self._value是一个promise,且then与当前promise.then相同 self = self._value; // 将传递的value替换为当前promise } if (Promise._onHandle) { // ? Promise._onHandle(self); } //console.log('state:'+self._state); if (self._state === 0) { // pending状态下,存储 defferred到_deferreds中 if (self._deferredState === 0) { self._deferredState = 1; self._deferreds = deferred; return; } if (self._deferredState === 1) { self._deferredState = 2; self._deferreds = [self._deferreds, deferred]; return; } self._deferreds.push(deferred); return; } handleResolved(self, deferred); // 非pending状态 } function handleResolved(self, deferred) { // 非pending状态下处理deferred asap(function() { // 延时执行 var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected; if (cb === null) { if (self._state === 1) { resolve(deferred.promise, self._value); } else { reject(deferred.promise, self._value); } return; } var ret = tryCallOne(cb, self._value); if (ret === IS_ERROR) { reject(deferred.promise, LAST_ERROR); } else { resolve(deferred.promise, ret); } }); } function resolve(self, newValue) { // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure if (newValue === self) { // resolve value不能是当前promise return reject( self, new TypeError('A promise cannot be resolved with itself.') ); } if ( // resolve value 是对象或函数 newValue && (typeof newValue === 'object' || typeof newValue === 'function') ) { var then = getThen(newValue); // 获取该对象的then if (then === IS_ERROR) { // 是错误类型,则拒绝 return reject(self, LAST_ERROR); } if ( // resolve value 是promise且和它的then和当前promise的then是相同的 then === self.then && newValue instanceof Promise ) { self._state = 3; // 当前promise状态为其它状态 self._value = newValue; finale(self); return; } else if (typeof then === 'function') { // resolve value的then属性是函数 doResolve(then.bind(newValue), self); return; } } self._state = 1; self._value = newValue; // 剩余情况, newValue是一个基本类型值 finale(self); } function reject(self, newValue) { self._state = 2; self._value = newValue; if (Promise._onReject) { Promise._onReject(self, newValue); } finale(self); } function finale(self) { // 遍历处理defferred if (self._deferredState === 1) { handle(self, self._deferreds); self._deferreds = null; } if (self._deferredState === 2) { for (var i = 0; i < self._deferreds.length; i++) { handle(self, self._deferreds[i]); } self._deferreds = null; } } function Handler(onFulfilled, onRejected, promise){ // 创建deferred this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null; this.onRejected = typeof onRejected === 'function' ? onRejected : null; this.promise = promise; } /** * Take a potentially misbehaving resolver function and make sure * onFulfilled and onRejected are only called once. * * Makes no guarantees about asynchrony. */ function doResolve(fn, promise) { var done = false; var res = tryCallTwo(fn, function (value) { // 首个promise创建时,回调函数有两个参数,resolve和reject, res为回调返回的值 if (done) return; done = true; resolve(promise, value); // resolve调用 }, function (reason) { if (done) return; done = true; reject(promise, reason); // reject调用 }); if (!done && res === IS_ERROR) { // 回调返回了一个错误,则拒绝 done = true; reject(promise, LAST_ERROR); } }

执行流程

第一: 创建promise对象

new Promise(function(resolve, reject){ console.log('callback...'); resolve(1); })

在代码中的执行顺序由图中的序号标明:
promise源码结构实例化.png
(请结合源码观察).
值得注意的是,实例化第一个promise对象时,若promise参数中同步resolve或reject,那么该promise在还没then之前,状态已从pending变成了fulfilled.

第二: 加载第一个then

pro.then(function(value){ // code... })

源代码执行流程:
promise源码结构then.png
可以看到,由于调用的promise的状态已为fullfilled,所以该promise并不会有defferred,所以进入了第4步handleResolved函数中,并开始第5步的延迟执行.控制权回到了第1步then函数中,并返回新的promise,开始下一个then调用.
第三: 加载第三个then
promise源码结构2then.png
可看到,这一步只有3个步骤,因为,调用该then的是上次调用then返回的promise,该promise的状态是pending.所以,它将此次promise回调保存到了defferreds.

第四: 延迟调用开始执行
当所有的then都执行完毕后,控制权会回到第二节的第5步,此时,第一个promise开始调用then中的回调,then中的回调resove或reject后,则开始执行它保存的defferred.

整个流程为:

new Promise() => doResolve() => tryCallTwo()

resolve() => 状态改变(pending->fulfilled) => finale()

=> then() => handle() => handleResolved() => asap() => return new promise

=> then() => handle() => 保存deferred => return new promise
重复第4步直到最后一个then…

  1. 控制权回到asap()
    => tryCallOne() => resolve(deferred.promise, ret) => 状态改变(pending->fulfilled) => finale() => handle() => handleResolved() => asap() => 重复5 => 直最后一个promise没有defferred,结束于finale()

实现一个简化版本

promise 的执行流程如下图:

169c500344dfe50a.png

/** * 实现一个Promise */ const PENDDING = 1 const FULFILLED = 2 const REJECTED = 3 class Promise { constructor(fn){ this.status = PENDDING this._value this.defferds = [] if(!fn) return this.doResolve(fn, this) } then(fulfill_cb, reject_cb) { let res = new Promise() let deferred = { promise: res, fulfilled: typeof fulfill_cb === 'function'? fulfill_cb : null, rejected: typeof reject_cb === 'function'? reject_cb : null } this.handle(this, deferred) return res } handle (self, deferred) { // 处理 deferred if(this.status === PENDDING) { // PENDDING 状态下,将 deferred 存入列表 this.defferds.push(deferred) } else { // promise 非 pendding 时处理 deferred this.handleResolved(self, deferred) } } handleResolved (self, deferred) { // 延时执行(new promise 回调内为同步执行,所以 promise 在进行 then 调用时很可能状态已非 PENDDING,此时则直接调用了 handleResoved 函数,为了保证 then 参数的函数异步执行,所以这里需延迟执行) setTimeout(() => { let cb = self.status === FULFILLED ? deferred.fulfilled : deferred.rejected if (cb === null) { if (self.state === FULFILLED) { self.resolve(deferred.promise, self._value); } else { self.reject(deferred.promise, self._value); } return; } var ret = cb(self._value) self.resolve(deferred.promise, ret) }, 4); } doResolve (fn, self) { var done = false fn(function(value){ if(done) return done = true self.resolve(self, value) }, function(value){ if(done) return done = true self.reject(self, value) }) } resolve(self, newValue) { if (newValue === self) return self.reject(self, new Error('A promise cannot be resolved with itself.')) // 这里只考虑 value是基本类型值的情况 self.status = FULFILLED self._value = newValue this.finale(self) } reject(self, newValue) { self.status = REJECTED self._value = newValue this.finale(self) } finale(self) { // 遍历处理 promise 的 deferred for (let i = 0; i < self.defferds.length; i++) { self.handle(self, self.defferds[i]); } self.defferds = [] } }

promise几个值得关注的地方

promise.resolve() 方法

promise.resolve 方法会返回一个状态为 resolve 的 Promise,根据参数分以下几种情况。

  1. 参数是一个基础类型值
promise.resolve(1)

resolve方法返回一个状态为 resolve 的 Promise,Promise的值为 1。

  1. 参数是一个 promise
promise.resolve(new Promise(function(){}))

resolve方法返回参数内的 Promise。

  1. 参数是一个 thenable (拥有then方法的对象)
var p1 = promise.resolve({then: function(onFulfill){onFulfill('fulfilled')}})

返回一个 Promise, 该 Promise 会 “跟随” 参数这个对象。

p1.then(function(v) { console.log(v); // 输出"fulfilled!" }, function(e) { // 不会被调用 });

new Primise() 内是同步执行的, promise.then() 是异步执行的

async function async1 () { return new Promise(resolve => { Promise.resolve().then(() => { async2().then(resolve) // 经过了两次异步才执行 resolve }) }).then(() => { console.log('async1 end') // 经过3次异步才执行 }) } async function async2 () { console.log('async2...'); // 经过一次异步 } async1() Promise.resolve() .then(function () { console.log('promise2') // 经过一次异步 }) .then(function () { console.log('promise3') // 经过两次异步 }) .then(function () { console.log('promise4') // 经过3次异步 }) console.log('ending...'); // 同步

控制台输出:

ending...
async2...
promise2
promise3
async1 end
promise4

resolve(Promise) “拆箱”是异步的,reject(Promise) 是同步的

var p1 = Promise.resolve( 1 ); var p2 = Promise.resolve( p1 ); var p3 = new Promise(function(resolve, reject){ resolve(1); }); var p4 = new Promise(function(resolve, reject){ resolve(p1); }); console.log(p1 === p2); console.log(p1 === p3); console.log(p1 === p4); console.log(p3 === p4); p4.then(function(value){ console.log('p4=' + value); }); p2.then(function(value){ console.log('p2=' + value); }) p1.then(function(value){ console.log('p1=' + value); })

控制台输出:

true
false
false
false
p2=1
p1=1
p4=1
var p1 = new Promise(function(resolve, reject){ resolve(Promise.resolve('resolve')); }); var p2 = new Promise(function(resolve, reject){ resolve(Promise.reject('reject')); }); var p3 = new Promise(function(resolve, reject){ reject(Promise.resolve('resolve')); }); p1.then( function fulfilled(value){ console.log('p1 fulfilled: ' + value); }, function rejected(err){ console.log('p1 rejected: ' + err); } ); p2.then( function fulfilled(value){ console.log('p2 fulfilled: ' + value); }, function rejected(err){ console.log('p2 rejected: ' + err); } ); p3.then( function fulfilled(value){ console.log('p3 fulfilled: ' + value); }, function rejected(err){ console.log('p3 rejected: ' + err); } );

控制台输出:

p3 rejected: [object Promise]
p1 fulfilled: resolve
p2 rejected: reject
😁😂😃😄😅😆😇😈😉😐😑😒😓😔😕😖😗😘😙😠😡😢😣😤😥😦😧😨😩😰😱😲😳😴😵😶😷😸😹🙀🙁🙂🙃🙄🙅🙆🙇🙈
🙂