彻底理解Javascript 中的 Promise

BerryTVB 3年前
   <p>ES6原生提供了 Promise 对象。</p>    <p>到底是何方妖怪呢?打出来看看:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/19763aae5de4d2fc5b4f4a5e87d46b2a.png"></p>    <p>所谓 Promise,就是一个对象,用来传递异步操作的消息。它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的 API,可供进一步处理。</p>    <p>Promise 对象有以下两个特点。</p>    <p>(1)对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态: Pending(进行中)、Resolved(已完成,又称 Fulfilled)和 Rejected(已失败) 。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是 Promise 这个名字的由来,它的英语意思就是「承诺」,表示其他手段无法改变。</p>    <p>(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。</p>    <p>有了 Promise 对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise 对象提供统一的接口,使得控制异步操作更加容易。</p>    <p>Promise 也有一些缺点。首先,无法取消 Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。第三,当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。</p>    <p>废话不多说,直接上demo:</p>    <pre>  <code class="language-javascript"><!DOCTYPE html>  <html>        <head>          <meta charset="utf-8" />          <title>Promise 学习笔记</title>          <script type="text/javascript">              window.onload = function() {                  function pms1() {                      return new Promise(function(resolve, reject) {                          setTimeout(function() {                              console.log('执行任务1');                              resolve('执行任务1成功');                          }, 2000);                      });                  }                    function pms2() {                      return new Promise(function(resolve, reject) {                          setTimeout(function() {                              console.log('执行任务2');                              resolve('执行任务2成功');                          }, 2000);                      });                  }                    function pms3() {                      return new Promise(function(resolve, reject) {                          setTimeout(function() {                              console.log('执行任务3');                              resolve('执行任务3成功');                          }, 2000);                      });                  }                  pms1().then(function(data) {                          console.log('第1个回调:' + data);                          return pms2();                      })                      .then(function(data) {                          console.log('第2个回调:' + data);                          return pms3();                      })                      .then(function(data) {                          console.log('第3个回调:' + data);                          return '还没完!该结束了吧!'                      }).then(function(data) {                          console.log(data);                      });              }          </script>      </head>        <body>        </body>    </html>  </code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/f63e2a975c10cbf8c6e9ef6278a237bb.png"></p>    <p>怎么样?是不是灰常简单啊!</p>    <p>demo2:</p>    <pre>  <code class="language-javascript"><!DOCTYPE html>  <html>        <head>          <meta charset="UTF-8">          <title></title>          <script type="text/javascript">              window.onload = function() {                  function pms1() {                      return new Promise(function(resolve, reject) {                          setTimeout(function() {                              var num = Math.ceil(Math.random() * 10); //生成1-10的随机数                              if(num <= 5) {                                  resolve(num);                              } else {                                  reject('数字太大了吧!');                              }                          }, 2000);                      });                  }                  setInterval(function() {                      pms1().then(function(data) {    //小于等于5的                          console.log(data);                      }, function(data) {     //大于的                          console.log(data);                      })                  }, 1000);              }          </script>      </head>        <body>      </body>    </html>  </code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/46cf8d20d2c168f813ddfa224cae0ee3.png"></p>    <p>Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 方法和 reject 方法。</p>    <p>如果异步操作成功,则用 resolve 方法将 Promise 对象的状态,从「未完成」变为「成功」(即从 pending 变为 resolved);</p>    <p>如果异步操作失败,则用 reject 方法将 Promise 对象的状态,从「未完成」变为「失败」(即从 pending 变为 rejected)。</p>    <p><strong>all的用法:</strong></p>    <p><strong>demo</strong>:</p>    <pre>  <code class="language-javascript"><!DOCTYPE html>  <html>        <head>          <meta charset="utf-8" />          <title>Promise 学习笔记</title>          <script type="text/javascript">              window.onload = function() {                  function pms1() {                      return new Promise(function(resolve, reject) {                          setTimeout(function() {                              console.log('执行任务1');                              resolve('执行任务1成功');                          }, 2000);                      });                  }                    function pms2() {                      return new Promise(function(resolve, reject) {                          setTimeout(function() {                              console.log('执行任务2');                              resolve('执行任务2成功');                          }, 2000);                      });                  }                    function pms3() {                      return new Promise(function(resolve, reject) {                          setTimeout(function() {                              console.log('执行任务3');                              resolve('执行任务3成功');                          }, 2000);                      });                  }                  Promise.all([pms1(), pms2(), pms3()]).then(function(data) {                      console.log(data);                      console.log({}.toString.call(data));                  })              }          </script>      </head>        <body>        </body>    </html>  </code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/cb8c37df6c7a1c3d3f087761e2178603.png"></p>    <p><strong>用Promise.all来执行,all接收一个数组参数,里面的值最终都算返回Promise对象。这样,三个异步操作的并行执行的,等到它们都执行完后才会进到then里面。那么,三个异步操作返回的数据哪里去了呢?都在then里面呢,all会把所有异步操作的结果放进一个 数组 中传给then,就是上面的results。</strong></p>    <h3><strong>race的用法</strong></h3>    <p>all方法的效果实际上是「谁跑的慢,以谁为准执行回调」,那么相对的就有另一个方法「谁跑的快,以谁为准执行回调」,这就是race方法,这个词本来就是赛跑的意思。race的用法与all一样,我们把上面runAsync1的延时改为1秒来看一下:</p>    <pre>  <code class="language-javascript"><!DOCTYPE html>  <html>        <head>          <meta charset="utf-8" />          <title>Promise 学习笔记</title>          <script type="text/javascript">              window.onload = function() {                  function pms1() {                      return new Promise(function(resolve, reject) {                          setTimeout(function() {                              console.log('执行任务1');                              resolve('执行任务1成功');                          }, 1000);                      });                  }                    function pms2() {                      return new Promise(function(resolve, reject) {                          setTimeout(function() {                              console.log('执行任务2');                              resolve('执行任务2成功');                          }, 2000);                      });                  }                    function pms3() {                      return new Promise(function(resolve, reject) {                          setTimeout(function() {                              console.log('执行任务3');                              resolve('执行任务3成功');                          }, 3000);                      });                  }                  Promise.race([pms1(), pms2(), pms3()]).then(function(data) {                      console.log(data);   //注意上面的延时时间                  })              }          </script>      </head>        <body>        </body>    </html>  </code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/824242914a3a554bd87d5a45d7d94b6b.png"></p>    <p>看到没: 只有第一个执行了回调!</p>    <p>在then里面的回调开始执行时,runAsync2()和runAsync3()并没有停止,仍旧再执行。于是再过1秒后,输出了他们结束的标志。</p>    <p>这个race有什么用呢?使用场景还是很多的,比如我们可以用race给某个异步请求设置超时时间,并且在超时后执行相应的操作。</p>    <p>再来看看jquery里面的 <strong>$.Deferred:</strong></p>    <p>jquery用$.Deferred实现了Promise规范,$.Deferred是个什么玩意呢?还是老方法,打印出来看看,先有个直观印象:</p>    <pre>  <code class="language-javascript">var def = $.Deferred();  console.log(def);  </code></pre>    <p>输出如下:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/18fe436cb5ad2dc74de5e58fe3b4bc32.png"></p>    <p>$.Deferred()返回一个对象,我们可以称之为Deferred对象,上面挂着一些熟悉的方法如:done、fail、then等。jquery就是用这个Deferred对象来注册异步操作的回调函数,修改并传递异步操作的状态。</p>    <p>Deferred对象的基本用法如下,为了不与ajax混淆,我们依旧举setTimeout的例子:</p>    <pre>  <code class="language-javascript"><!doctype html>  <html lang="en">        <head>          <meta charset="UTF-8" />          <title>Document</title>          <script type="text/javascript" src="js/jquery-3.1.1.min.js"></script>          <script type="text/javascript">              $(function() {                  function runAsync() {                      var def = $.Deferred();                      setTimeout(function() {                          console.log('执行完成');                          def.resolve('随便什么数据');                      }, 2000);                      return def;                  }                  runAsync().then(function(data) {                      console.log(data)                  });              })          </script>      </head>        <body>        </body>    </html>  </code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/e7f909e7e693f07ef9e27cfdc8e015e2.png"></p>    <p><strong>在runAsync函数中,我们首先定义了一个def对象,然后进行一个延时操作,在2秒后调用def.resolve(),最后把def作为函数的返回。调用runAsync的时候将返回def对象,然后我们就可以.then来执行回调函数。</strong></p>    <p>是不是感觉和ES6的Promise很像呢?</p>    <p>区别在何处一看便知。由于jquery的def对象本身就有resolve方法,所以我们在创建def对象的时候并未像ES6这样传入了一个函数参数,是空的。在后面可以直接def.resolve()这样调用。</p>    <pre>  <code class="language-javascript"><!doctype html>  <html lang="en">        <head>          <meta charset="UTF-8" />          <title>Document</title>          <script type="text/javascript" src="js/jquery-3.1.1.min.js"></script>          <script type="text/javascript">              $(function() {                  function runAsync() {                      var def = $.Deferred();                      setTimeout(function() {                          console.log('执行完成');                          def.resolve('随便什么数据');                      }, 2000);                      return def;                  }                  var pms=runAsync();                  pms.then(function(data) {                      console.log(data)                  });                  pms.resolve('我穿越了!')              })          </script>      </head>        <body>        </body>    </html>  </code></pre>    <p><img src="https://simg.open-open.com/show/f81ca51b937ab18ac669e4838552df3c.png"></p>    <p>这样也有一个弊端,因为执行runAsync()可以拿到def对象,而def对象上又有resolve方法,那么岂不是可以在外部就修改def的状态了?比如我把上面的代码修改如下:</p>    <p>现象会如何呢?并不会在2秒后输出“执行完成”,而是直接输出“我穿越了”。因为我们在异步操作执行完成之前,没等他自己resolve,就在外部给resolve了。这显然是有风险的,比如你定义的一个异步操作并指定好回调函数,有可能被别人给提前结束掉,你的回调函数也就不能执行了。</p>    <p>怎么办?jquery提供了一个promise方法,就在def对象上,他可以返回一个受限的Deferred对象,所谓受限就是没有resolve、reject等方法,无法从外部来改变他的状态,用法如下:</p>    <pre>  <code class="language-javascript"><!doctype html>  <html lang="en">        <head>          <meta charset="UTF-8" />          <title>Document</title>          <script type="text/javascript" src="js/jquery-3.1.1.min.js"></script>          <script type="text/javascript">              $(function() {                  function runAsync() {                      var def = $.Deferred();                      setTimeout(function() {                          console.log('执行完成');                          def.resolve('随便什么数据');                      }, 2000);                      return def.promise();                  }                  var pms=runAsync();                  pms.then(function(data) {                      console.log(data)                  });                  //pms.resolve('我穿越了!');    //这一句会报错jquery-3.1.1.min.js:2 Uncaught TypeError: pms.resolve is not a function              })          </script>      </head>        <body>        </body>    </html>  </code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/ecbca74fb06f76810378c3f9379d317c.png"></p>    <p> </p>    <h3><strong>then的链式调用</strong></h3>    <p>既然Deferred也是Promise规范的实现者,那么其他特性也必须是支持的。链式调用的用法如下:</p>    <pre>  <code class="language-javascript"><!doctype html>  <html lang="en">        <head>          <meta charset="UTF-8" />          <title>Document</title>          <script type="text/javascript" src="js/jquery-3.1.1.min.js"></script>          <script type="text/javascript">              $(function() {                  function runAsync() {                      var def = $.Deferred();                      setTimeout(function() {                          console.log('执行完成');                          def.resolve('随便什么数据');                      }, 2000);                      return def.promise();                  }                  var pms = runAsync();                    pms.then(function(data) {                          console.log('1:' + data);                          return runAsync();                      })                      .then(function(data) {                          console.log('2:' + data);                          return runAsync();                      })                      .then(function(data) {                          console.log('3:' + data);                      });                  //pms.resolve('我穿越了!');    //这一句会报错jquery-3.1.1.min.js:2 Uncaught TypeError: pms.resolve is not a function              })          </script>      </head>        <body>        </body>    </html>  </code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/c1cd8bd4307f42d8a83a18a7687ce725.png"></p>    <h3><strong>done与fail</strong></h3>    <p>我们知道,Promise规范中,then方法接受两个参数,分别是执行完成和执行失败的回调,而jquery中进行了增强,还可以接受第三个参数,就是在pending状态时的回调,如下:</p>    <pre>  <code class="language-javascript">deferred.then( doneFilter [, failFilter ] [, progressFilter ] )  </code></pre>    <p>除此之外,jquery还增加了两个语法糖方法,done和fail,分别用来指定执行完成和执行失败的回调,也就是说这段代码:</p>    <pre>  <code class="language-javascript">d.then(function(){      console.log('执行完成');  }, function(){      console.log('执行失败');  });  </code></pre>    <p>与这段代码是等价的:</p>    <pre>  <code class="language-javascript">d.done(function(){      console.log('执行完成');  })  .fail(function(){      console.log('执行失败');  });</code></pre>    <p><strong>always的用法</strong></p>    <p>jquery的Deferred对象上还有一个always方法,不论执行完成还是执行失败,always都会执行,有点类似ajax中的complete。不赘述了。</p>    <p><strong>$.when的用法</strong></p>    <p>jquery中,还有一个$.when方法来实现Promise,与ES6中的all方法功能一样,并行执行异步操作,在所有的异步操作执行完后才执行回调函数。不过$.when并没有定义在$.Deferred中,看名字就知道,$.when,它是一个单独的方法。与ES6的all的参数稍有区别,它接受的并不是数组,而是多个Deferred对象,如下:</p>    <pre>  <code class="language-javascript">$.when(runAsync(), runAsync2(), runAsync3())  .then(function(data1, data2, data3){      console.log('全部执行完成');      console.log(data1, data2, data3);  });  </code></pre>    <p>jquery中没有像ES6中的race方法吗?就是以跑的快的为准的那个方法。对的,jquery中没有。</p>    <p>以上就是jquery中Deferred对象的常用方法了,还有一些其他的方法用的也不多,干脆就不记它了。接下来该说说ajax了。</p>    <h3><strong>ajax与Deferred的关系</strong></h3>    <p>jquery的ajax返回一个受限的Deferred对象,还记得受限的Deferred对象吧,也就是没有resolve方法和reject方法,不能从外部改变状态。想想也是,你发一个ajax请求,别人从其他地方给你取消掉了,也是受不了的。</p>    <p>既然是Deferred对象,那么我们上面讲到的所有特性,ajax也都是可以用的。比如链式调用,连续发送多个请求:</p>    <pre>  <code class="language-javascript">req1 = function(){      return $.ajax(/*...*/);  }  req2 = function(){      return $.ajax(/*...*/);  }  req3 = function(){      return $.ajax(/*...*/);  }    req1().then(req2).then(req3).done(function(){      console.log('请求发送完毕');  });</code></pre>    <p>明白了ajax返回对象的实质,那我们用起来就得心应手了。</p>    <p>success、error与complete</p>    <p>这三个方法或许是我们用的最多的,使用起来是这样的:</p>    <pre>  <code class="language-javascript">$.ajax(/*...*/)  .success(function(){/*...*/})  .error(function(){/*...*/})  .complete(function(){/*...*/})  </code></pre>    <p>分别表示ajax请求成功、失败、结束的回调。这三个方法与Deferred又是什么关系呢?其实就是语法糖,success对应done,error对应fail,complete对应always,就这样,只是为了与ajax的参数名字上保持一致而已,更方便大家记忆,看一眼源码:</p>    <pre>  <code class="language-javascript">deferred.promise( jqXHR ).complete = completeDeferred.add;  jqXHR.success = jqXHR.done;  jqXHR.error = jqXHR.fail;  </code></pre>    <p>complete那一行那么写,是为了减少重复代码,其实就是把done和fail又调用一次,与always中的代码一样。deferred.promise( jqXHR )这句也能看出,ajax返回的是受限的Deferred对象。</p>    <p>jquery加了这么些个语法糖,虽然上手门槛更低了,但是却造成了一定程度的混淆。一些人虽然这么写了很久,却一直不知道其中的原理,在面试的时候只能答出一些皮毛,这是很不好的。这也是我写这篇文章的缘由。</p>    <p>看一个promise.js库:</p>    <pre>  <code class="language-javascript">/*!   * Promise JavaScript Library v2.0.0   */  ;  (function(window) {      var _promise = function(thens) {          this.thens = thens || [];          this.state = "";            this._CONSTANT = {              any: "any",              number: "number",              resolved: "resolved",              rejected: "rejected",              pending: "pending"          };      };        _promise.prototype = {          resolve: function() {              if(this.state == this._CONSTANT.pending) {                  this.state = this._CONSTANT.resolved;                  return;              }              if(this.state !== "") return;              if(this.promiseArr) {                  for(var i = 0, j = this.promiseArr.length; i < j; i++) {                      this.promiseArr[i].resolveCount++;                  }                  if(this.promiseArr[0].action !== this._CONSTANT.any) {                      if(this.resolveCount !== this.promiseArr.length) {                          return;                      }                  } else {                      if(this.resolveCount > 1) {                          return;                      }                  }              }              this.state = this._CONSTANT.resolved;              if(!this.thens) return;              if(this.thens[0] && this.thens[0].finallyCB) this.thens[0].finallyCB.apply(null, arguments);              var t, n;              while(t = this.thens.shift()) {                  if(typeof t === this._CONSTANT.number) {                      var self = this;                      setTimeout(function() {                          var prms = new _promise(self.thens);                          prms.resolve();                      }, t);                      break;                  }                  var doneFn = t.done,                      action = t.action;                  if(!doneFn) continue;                  if(doneFn instanceof Array) {                      var arr = [];                      for(var i = 0, j = doneFn.length; i < j; i++) {                          var df = doneFn[i];                          if(df instanceof _promise) {                              df.thens = this.thens;                              arr.push(df);                          } else {                              var m = df.apply(null, arguments);                              if(m instanceof _promise) {                                  m.thens = this.thens;                                  arr.push(m);                              }                          }                      }                      var l = arr.length;                      if(l === 0) {                          continue;                      } else {                          for(var i = 0; i < l; i++) {                              arr[i].promiseArr = arr;                              arr[i].action = action;                              arr[i].resolveCount = 0;                          }                          break;                      }                  } else {                      if(doneFn instanceof _promise) {                          doneFn.thens = this.thens;                          break;                      } else {                          n = doneFn.apply(null, arguments);                          if(n instanceof _promise) {                              n.thens = this.thens;                              break;                          }                      }                      continue;                  }                }          },            reject: function() {              if(this.state !== "") return;              if(this.promiseArr && this.promiseArr[0].action === this._CONSTANT.any) {                  if(this.promiseArr[this.promiseArr.length - 1] !== this) {                      return;                  }              }              this.state = this._CONSTANT.rejected;              if(!this.thens) return;              if(this.thens[0] && this.thens[0].finallyCB) this.thens[0].finallyCB.apply(null, arguments);              var t, n;              while(t = this.thens.shift()) {                  if(typeof t === this._CONSTANT.number) {                      var self = this;                      setTimeout(function() {                          var prms = new _promise(self.thens);                          prms.resolve();                      }, t);                      break;                  }                  if(t.fail) {                      n = t.fail.apply(null, arguments);                      if(n instanceof _promise) {                          n.thens = this.thens;                          break;                      }                      continue;                  }                  break;              }          },            notify: function() {              var t = this.thens[0];              t.progress.apply(null, arguments);          },            then: function(done, fail, progress) {              this.thens.push({                  done: done,                  fail: fail,                  progress: progress              });              return this;          },            any: function(done, fail, progress) {              this.thens.push({                  done: done,                  fail: fail,                  progress: progress,                  action: this._CONSTANT.any              });              return this;          },            done: function(done) {              if(this.thens.length === 0 || this.thens[this.thens.length - 1].done) {                  this.thens.push({                      done: done                  });              } else {                  this.thens[this.thens.length - 1].done = done;              }              return this;          },            fail: function(fail) {              if(this.thens.length === 0 || this.thens[this.thens.length - 1].fail) {                  this.thens.push({                      fail: fail                  });              } else {                  this.thens[this.thens.length - 1].fail = fail;              }              return this;          },            progress: function(progress) {              if(this.thens.length === 0 || this.thens[this.thens.length - 1].progress) {                  this.thens.push({                      progress: progress                  });              } else {                  this.thens[this.thens.length - 1].progress = progress;              }              return this;          },            ensure: function(finallyCB) {              if(this.thens.length === 0 || this.thens[this.thens.length - 1].finallyCB) {                    this.thens.push({                      finallyCB: finallyCB                  });              } else {                  this.thens[this.thens.length - 1].finallyCB = finallyCB;              }              return this;          },            always: function(alwaysCB, progress) {              this.thens.push({                  done: alwaysCB,                  fail: alwaysCB,                  progress: progress              });              return this;          },            wait: function(ms) {              this.thens.push(~~ms);              return this;          }      }        var Promise = function(parameter) {          var prms = new _promise();          if(parameter) {              if(arguments.length > 1) {                  prms.thens[0] = {};                  prms.thens[0].done = [];                  prms.thens[0].done.push.apply(prms.thens[0].done, arguments);                  setTimeout(function() {                      prms.resolve();                  }, 1)              } else {                  prms = parameter();                  if(prms instanceof _promise) return prms;              }          }          return prms;      };        Promise.when = function() {          var prms = new _promise();          prms.thens[0] = {};          prms.thens[0].done = [];          prms.thens[0].done.push.apply(prms.thens[0].done, arguments);          setTimeout(function() {              prms.resolve();          }, 1)          return prms;      };        Promise.any = function() {          var prms = new _promise();          prms.thens[0] = {};          prms.thens[0].action = prms._CONSTANT.any;          prms.thens[0].done = [];          prms.thens[0].done.push.apply(prms.thens[0].done, arguments);          setTimeout(function() {              prms.resolve();          }, 1)          return prms;      };        Promise.timeout = function(promise, ms) {          setTimeout(function() {              promise.reject();          }, ms);          return promise;      }        Promise.gtTime = function(promise, ms) {          promise.state = promise._CONSTANT.pending;          setTimeout(function() {              if(promise.state == promise._CONSTANT.resolved) {                  promise.state = "";                  promise.resolve();              }              promise.state = "";          }, ms);          return promise;      }        if(typeof module === "object" && module && typeof module.exports === "object") {          module.exports = Promise;      } else {          window.Promise = Promise;            if(typeof define === "function" && define.amd) {              define("promise", [], function() {                  return Promise;              });          }      }  }(window));  </code></pre>    <p>promise.js提供了done和resolve方法,done负责注册成功的回调函数,resolve负责触发。</p>    <pre>  <code class="language-javascript">function cb() {              alert('success')          }          var prms = Promise()          prms.done(cb)          setTimeout(function() {              prms.resolve()          }, 3000)</code></pre>    <p>在3秒之后,浏览器将alert  “success”。</p>    <p>当然你也可以通过prms.resolve(“xxx”)传递参数给cb函数使用,如:</p>    <pre>  <code class="language-javascript">  function cb(num) {              alert(num)          }          var prms = Promise()          prms.done(cb)          setTimeout(function() {              prms.resolve(1)          }, 3000)</code></pre>    <p>在3秒之后,浏览器将alert  “1”。</p>    <h2><strong>fail/reject</strong></h2>    <p>fail函数负责注册失败的回调函数,reject负责触发。如:</p>    <pre>  <code class="language-javascript">  function cb() {              alert('fail')          }          var prms = Promise()          prms.fail(cb)          setTimeout(function () {              prms.reject()          }, 3000)</code></pre>    <h2><strong>progress/notify</strong></h2>    <p>progress函数负责注册处理中进度的回调函数,notify负责触法。如:</p>    <pre>  <code class="language-javascript"> function cb() {              alert('progress')          }          var prms = Promise()          prms.progress(cb)          setInterval(function() {              prms.notify()          }, 2000)</code></pre>    <p>每隔两秒浏览器会弹出一个progress。</p>    <h2><strong>chain</strong></h2>    <pre>  <code class="language-javascript">  function cb1() {              alert('success')          }          function cb2() {              alert('fail')          }          function cb3() {              alert('progress')          }          var prms = Promise();          prms.done(cb1).fail(cb2).progress(cb3)          setTimeout(function () {              prms.resolve()              //prms.reject()              //prms.notify()            }, 3000)</code></pre>    <h2><strong>then</strong></h2>    <pre>  <code class="language-javascript">function fn1() {              alert('success')          }          function fn2() {              alert('fail')          }          function fn3() {              alert('progress')          }          var prms = Promise()          prms.then(fn1, fn2, fn3)          prms.resolve()          prms.reject()          prms.notify()</code></pre>    <p>当然也支持prms.then().then().then()……….</p>    <p>当then的第一个参数为一个数组的时候,要等所有task都完成:</p>    <pre>  <code class="language-javascript">f1().then([f2_1, f2_2]).then(f3)</code></pre>    <p>如上面的代码:</p>    <p>f1执行完后,同时执行f2_1和f2_2,当f2_1和f2_2 <strong> 全部 </strong> 都执行完成才会执行f3。</p>    <h2><strong>any</strong></h2>    <pre>  <code class="language-javascript">f1().any([f2_1, f2_2]).then(f3)</code></pre>    <p>f1执行完后,同时执行f2_1和f2_2,当f2_1和f2_2中的 <strong>任意一个</strong> 执行完成才会执行f3。</p>    <h2><strong>always</strong></h2>    <pre>  <code class="language-javascript">  var prms = Promise()          prms.always(function () {              alert(2)          })          setTimeout(function () {              // prms.resolve()              prms.reject()          }, 3000)</code></pre>    <p>always(fn)等同于then(fn,fn),也等同于done(fn).fail(fn)</p>    <h2><strong>wait</strong></h2>    <pre>  <code class="language-javascript"> function f10() {              var promise = Promise();              setTimeout(function () {                    console.log(10);                  promise.resolve();              }, 4500)                return promise;          }            function f11() {              var promise = Promise();              setTimeout(function () {                    console.log(11);                  promise.resolve();              }, 1500)                return promise;          }            f11().wait(5000).then(f10)  //execute f11 then wait 5000ms then execute f10</code></pre>    <h2><strong>ensure</strong></h2>    <p>ensure方法类似try…catch..finally中的finally,不管task成功失败都会执行。</p>    <h2><strong>Promise.when</strong></h2>    <pre>  <code class="language-javascript"> Promise.when(f1(), f2()).then(f3).then(f4)                  function f1() {              var promise = Promise();              setTimeout(function () {                    console.log(1);                  promise.resolve("from f1");              }, 1500)                return promise;          }            function f2() {              var promise = Promise();              setTimeout(function () {                    console.log(2);                  promise.resolve();              }, 5500)                return promise;          }            function f3() {              var promise = Promise();              setTimeout(function () {                    console.log(3);                  promise.resolve();              }, 1500)                return promise;            }            function f4() {              var promise = Promise();              setTimeout(function () {                    console.log(4);                  promise.resolve();              }, 1500)                return promise;          }</code></pre>    <p>上面promise.when的等同简略写法也可以是:Promise(f1(),f2()).then….</p>    <h2><strong>Promise.any</strong></h2>    <p>Promise.any的使用和when一样,when的意义是等所有task都完成再执行后面的task,而any的意义是任何一个task完成就开始执行后面的task。</p>    <h2><strong>Promise.timeout</strong></h2>    <pre>  <code class="language-javascript">  Promise.timeout(f1(), 2000).then(f2, function () {              alert("timeout");          }).wait(5000).then(f3);          function f1() {              var promise = Promise();              setTimeout(function () {                    console.log(1);                  promise.resolve("from f1");              }, 1500)                return promise;          }            function f2() {              var promise = Promise();              setTimeout(function () {                    console.log(2);                  promise.resolve();              }, 1500)                return promise;          }            function f3() {              var promise = Promise();              setTimeout(function () {                    console.log(3);                  promise.resolve();              }, 1500)                return promise;            }</code></pre>    <h2><strong>with wind.js</strong></h2>    <pre>  <code class="language-javascript">  <script src="wind-all-0.7.3.js"></script>      <script src="promise.js"></script>      <script>            Wind.Promise.create = function (fn) {              var prms = Promise();              fn(prms.resolve, prms.reject);              return prms;          }            var testAsync = eval(Wind.compile("promise", function () {              for (var i = 0; i < 3; i++) {   //loop 3 times                  var aa = $await(f1());                  alert(aa);                  //alert “from f1”                   $await(f2().wait(3000));    //execute f2 then wait 3000ms                  $await(f3());              }          }));            testAsync();            function f1() {              var promise = Promise();              setTimeout(function () {                  console.log(1);                  promise.resolve("from f1");              }, 2500)                return promise;          }            function f2() {              var promise = Promise();              setTimeout(function () {                  console.log(2);                  promise.resolve();              }, 1500)                return promise;          }            function f3() {              var promise = Promise();              setTimeout(function () {                  console.log(3);                  promise.resolve();              }, 1500)                return promise;          }      </script></code></pre>    <p>That’s all.Have Fun!</p>    <p> </p>    <p>来自:http://www.cnblogs.com/libin-1/p/5947602.html</p>    <p> </p>