先来看下 Promise 的常见应用:
观察者模式 观察上面的这个例子,我们来分析 Promise 的调用流程:
构造方法接受一个 executor 函数,在 new Promise 的时候这个 executor 立即执行 
executor 内部的异步任务被放入微任务队列等待执行 
then 被执行,收集成功/失败回调,放入成功/失败队列 
executor 的异步任务被执行,触发resolve/reject,从成功/失败队列中取出回调依次执行 
 
由上面的分析得知这是一种典型的观察者模式 。这是典型的“收集依赖->触发依赖->取出依赖执行”的方式,在 Promise 中执行顺序是 “then收集依赖->异步触发resolve->resolve执行依赖”。由此我们可以勾勒出 Promise 的大致形状:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class  Promise {    constructor (executor ){         this .resolveQueue  = [];          this .rejectQueue  = [];          let  resolve  = val => {             while  (this .resolveQueue .length ) {                 const  callback = this .resolveQueue .shift ();                 callback (val);             }         };         let  reject  = val => {             while  (this .rejectQueue .length ) {                 const  callback = this .rejectQueue .shift ();                 callback (val);             }         };         executor (resolve,reject);     }          then (resolveFn,rejectFn ){         this .resolveQueue .push (resolveFn);         this .rejectQueue .push (rejectFn);     } } 
Promise A+规范 以上,我们用观察者模式简单实现了能够在then方法的回调中取得异步操作的返回值,下面我们使用Promise A+规范来补充下这个Promise。
Promise 本质是一个状态机,且状态只能为以下三种:Pending(等待态)、Fulfilled(执行态)、Rejected(拒绝态),状态的变更是单向的,只能从 Pending -> Fulfilled 或 Pending -> Rejected,状态变更不可逆
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 class  Promise {    constructor (executor ){         this .status  = PENDING ;         this .resolveQueue  = [];          this .rejectQueue  = [];          let  resolve  = val => {                         if  (this .status  !== PENDING ) return ;              this .status  = FULFILLED ;                           while  (this .resolveQueue .length ) {                 const  callback = this .resolveQueue .shift ();                 callback (val);             }         };         let  reject  = val => {             if  (this .status  !== PENDING ) return ;             this .status  = REJECTED ;                          while  (this .rejectQueue .length ) {                 const  callback = this .rejectQueue .shift ();                 callback (val);             }         };         executor (resolve,reject);     }          then (resolveFn,rejectFn ){         this .resolveQueue .push (resolveFn);         this .rejectQueue .push (rejectFn);     } } 
then的链式调用 先来看个简单的例子:
思考下如何实现这种链式调用:
promise可以不断地then下去,说明then方法本身会返回一个Promise,那些直接return 一个值的也会被包装为Promise  
then的回调需要按顺序执行。以上面的代码为例,虽然中间return了一个Promise,但执行的顺序仍然要保证是1-2-3,我们需要等待Promise的状态变更后再执行下一个then收集的回调 
 
对then方法进行如下改写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 then (resolveFn, rejectFn ) {    return  new  Promise ((resolve, reject ) =>  {                  const  fulfilledFn  = value => {             try  {                                  const  x = resolveFn (value);                                  x instanceof  Promise  ? x.then (resolve, reject) : resolve (x);             } catch  (err) {                 reject (err);             }         };                  this .resolveQueue .push (fulfilledFn);         const  rejectedFn  = error => {             try  {                 const  x = rejectFn (error);                 x instanceof  Promise  ? x.then (resolve, reject) : resolve (x);             } catch  (err) {                 reject (err);             }         };         this .rejectQueue .push (rejectedFn);     }); } 
值穿透 & 状态已变更情况 值穿透:根据规范,如果then接受的函数不是function,那么我们应该忽略它。如果没有忽略,当then回调不为function的时候会抛出异常,导致链式调用中断。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 then (resolveFn, rejectFn ) {    return  new  Promise ((resolve, reject ) =>  {                  if  (typeof  resolveFn !== 'function' ) {             resolveFn = value  =>         }         if  (typeof  rejectFn !== 'function' ) {             rejectFn = reason  =>                 throw  new  Error (reason instanceof  Error  ? reason.message  : reason);             };         }                  const  fulfilledFn  = value => {             try  {                                  const  x = resolveFn (value);                                  x instanceof  Promise  ? x.then (resolve, reject) : resolve (x);             } catch  (err) {                 reject (err);             }         };         const  rejectedFn  = error => {             try  {                 const  x = rejectFn (error);                 x instanceof  Promise  ? x.then (resolve, reject) : resolve (x);             } catch  (err) {                 reject (err);             }         };         switch  (this .status ) {                          case  PENDING :                 this .resolveQueue .push (fulfilledFn);                 this .rejectQueue .push (rejectedFn);                 break ;                          case  FULFILLED :                 fulfilledFn (this .value );                  break ;             case  REJECTED :                 rejectedFn (this .value );                 break ;         }     }); } 
兼容同步任务 完成了 then 的链式调用以后,我们再处理一个前边的细节,然后放出完整代码。上文我们说过,Promise 的执行顺序是 new Promise -> then()回调收集 -> resolve/reject执行回调。这一顺序是建立在executor是异步任务 的前提上的。如果executor是一个同步任务,那么执行顺序会变成new Promise -> resolve/reject的回调 -> then收集回调(即resolve的执行跑到then前面去了,从而导致我们无法在then中得到Promise的resolve的值)。
为了兼容上述情况,我们给resolve/reject执行回调的操作包装一个setTimeout让其异步执行:
这里插一句,有关这个 setTimeout,其实还有一番学问。虽然规范没有要求回调应该被放进宏任务队列还是微任务队列,但其实 Promise 的默认实现是放进了微任务队列,我们的实现(包括大多数 Promise 手动实现和 polyfill 的转化)都是使用 setTimeout 放入了宏任务队列(当然我们也可以用 MutationObserver 模拟微任务)
 
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 const  PENDING  = 'pending' ;const  FULFILLED  = 'fulfilled' ;const  REJECTED  = 'rejected' ;class  Promise  {         constructor (executor ) {         this ._status  = PENDING ;             this ._value  = undefined ;         this ._resolveQueue  = [];             this ._rejectQueue  = [];                       let  _resolve  = val => {                          const  run  = (                 if  (this ._status  !== PENDING ) return ;                 this ._status  = FULFILLED ;                             this ._value  = val;                                                                     while  (this ._resolveQueue .length ) {                     const  callback = this ._resolveQueue .shift ();                     callback (val);                 }             };             setTimeout (run);         };                  let  _reject  = val => {             const  run  = (                 if  (this ._status  !== PENDING ) return ;                 this ._status  = REJECTED ;                              this ._value  = val;                                    while  (this ._rejectQueue .length ) {                     const  callback = this ._rejectQueue .shift ();                     callback (val);                 }             };             setTimeout (run);         };                  executor (_resolve, _reject);     }          then (resolveFn, rejectFn ) {                  typeof  resolveFn !== 'function'  ? resolveFn = value  =>null ;         typeof  rejectFn !== 'function'  ? rejectFn = reason  =>             thrownewError (reason instanceof  Error  ? reason.message  : reason);         } : null ;                  return  new  Promise ((resolve, reject ) =>  {                          const  fulfilledFn  = value => {                 try  {                                          let  x = resolveFn (value);                                          x instanceof  Promise  ? x.then (resolve, reject) : resolve (x)                 } catch  (error) {                     reject (error)                 }             };                          const  rejectedFn  = error => {                 try  {                     let  x = rejectFn (error);                     x instanceof  Promise  ? x.then (resolve, reject) : resolve (x)                 } catch  (error) {                     reject (error)                 }             };             switch  (this ._status ) {                                  case  PENDING :                     this ._resolveQueue .push (fulfilledFn);                     this ._rejectQueue .push (rejectedFn);                     break ;                                  case  FULFILLED :                     fulfilledFn (this ._value );                         break ;                 case  REJECTED :                     rejectedFn (this ._value );                     break ;             }         })     } } 
测试:
Promise中的其他方法 以上我们就实现了Promise的主要功能,剩下的几个方法都非常简单:
Promise.prototype.catch,返回一个 Promise,并且处理拒绝的情况。它的行为与调用Promise.prototype.then(undefined, onRejected)相同:
1 2 3 4 catch  (rejectFn) {    return  this .then (null , rejectFn); } 
Promise.prototype.finally()返回一个 Promise。在 promise 结束时,无论结果是 fulfilled 或者是 rejected,都会执行指定的回调函数。在 finally 之后,还可以继续 then。并且会将值原封不动的传递给后面的then。
1 2 3 4 5 6 finally (callback ) {    return  this .then (         value  =>new  Promise (resolve  =>resolve (callback ())).then (() =>  value),         reason  =>new  Promise (resolve  =>resolve (callback ()).then (() =>  throw  reason))     ); } 
Promise.resolve()返回一个以给定值解析后的 Promise 对象。如果该值为 promise,返回这个 promise;如果这个值是 thenable(即带有”then” 方法)),返回的 promise 会“跟随”这个 thenable 的对象,采用它的最终状态;否则返回的 promise 将以此值完成。此函数将类 promise 对象的多层嵌套展平。
1 2 3 4 static  resolve (value ) {         return  value instanceof  Promise  ? value : new  Promise (resolve  =>resolve (value)); } 
Promise.reject()方法返回一个带有拒绝原因的 Promise 对象。
1 2 3 static  reject (reason ) {    return  new  Promise ((resolve, reject ) =>  reject (reason)); } 
Promise.all(iterable)方法返回一个 Promise 实例,此实例在 iterable 参数内所有的 promise 都“完成(resolved)”或参数中不包含 promise 时回调完成(resolve);如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败 promise 的结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 static  all (promiseArr ) {    let  index = 0 ;     let  results = [];     return  new  Promise ((resolve, reject ) =>  {         for  (let  i = 0 ; i < promiseArr.length ; i++) {                          Promise .resolve (promiseArr[i]).then (                 value  =>                     index++;                     results[i] = value;                                          if  (index === promiseArr.length ) {                         resolve (results);                     }                 },                 err  =>                                          reject (err);                 }             )         }     }); } 
Promise.race(iterable)方法返回一个 promise,一旦迭代器中的某个 promise 解决或拒绝,返回的 promise 就会解决或拒绝。
1 2 3 4 5 6 7 8 9 10 11 static  race (promiseArr ) {         return  new  Promise ((resolve, reject ) =>  {         for  (const  p of  promiseArr) {             Promise .resolve (p).then (                 value  =>resolve (value),                 err  =>reject (err)             )         }     }) } 
完整代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 const  PENDING  = 'pending' ;const  FULFILLED  = 'fulfilled' ;const  REJECTED  = 'rejected' ;class  Promise  {         constructor (executor ) {         this ._status  = PENDING ;             this ._value  = undefined ;         this ._resolveQueue  = [];             this ._rejectQueue  = [];                       let  _resolve  = val => {                          const  run  = (                 if  (this ._status  !== PENDING ) return ;                 this ._status  = FULFILLED ;                             this ._value  = val;                                                                     while  (this ._resolveQueue .length ) {                     const  callback = this ._resolveQueue .shift ();                     callback (val);                 }             };             setTimeout (run);         };                  let  _reject  = val => {             const  run  = (                 if  (this ._status  !== PENDING ) return ;                 this ._status  = REJECTED ;                              this ._value  = val;                                    while  (this ._rejectQueue .length ) {                     const  callback = this ._rejectQueue .shift ();                     callback (val);                 }             };             setTimeout (run);         };                  executor (_resolve, _reject);     }          then (resolveFn, rejectFn ) {                  typeof  resolveFn !== 'function'  ? resolveFn = value  =>null ;         typeof  rejectFn !== 'function'  ? rejectFn = reason  =>             thrownewError (reason instanceof  Error  ? reason.message  : reason);         } : null ;                  return  new  Promise ((resolve, reject ) =>  {                          const  fulfilledFn  = value => {                 try  {                                          let  x = resolveFn (value);                                          x instanceof  Promise  ? x.then (resolve, reject) : resolve (x)                 } catch  (error) {                     reject (error)                 }             };                          const  rejectedFn  = error => {                 try  {                     let  x = rejectFn (error);                     x instanceof  Promise  ? x.then (resolve, reject) : resolve (x)                 } catch  (error) {                     reject (error)                 }             };             switch  (this ._status ) {                                  case  PENDING :                     this ._resolveQueue .push (fulfilledFn);                     this ._rejectQueue .push (rejectedFn);                     break ;                                  case  FULFILLED :                     fulfilledFn (this ._value );                         break ;                 case  REJECTED :                     rejectedFn (this ._value );                     break ;             }         })     }          catch (rejectFn) {         return  this .then (null , rejectFn);     }     finally (callback ) {         return  this .then (             value  =>new  Promise (resolve  =>resolve (callback ())).then (() =>  value),             reason  =>new  Promise (resolve  =>resolve (callback ()).then (() =>  throw  reason))         );     }     static  resolve (value ) {                  return  value instanceof  Promise  ? value : new  Promise (resolve  =>resolve (value));     }     static  reject (reason ) {         return  new  Promise ((resolve, reject ) =>  reject (reason));     }     static  all (promiseArr ) {         let  index = 0 ;         let  results = [];         return  new  Promise ((resolve, reject ) =>  {             for  (let  i = 0 ; i < promiseArr.length ; i++) {                                  Promise .resolve (promiseArr[i]).then (                     value  =>                         index++;                         results[i] = value;                                                  if  (index === promiseArr.length ) {                             resolve (results);                         }                     },                     err  =>                                                  reject (err);                     }                 )             }         });     }     static  race (promiseArr ) {                  return  new  Promise ((resolve, reject ) =>  {             for  (const  p of  promiseArr) {                 Promise .resolve (p).then (                     value  =>resolve (value),                     err  =>reject (err)                 )             }         })     } }