ES6 Promise 接口

構造函數

new Promise(function(resolve, reject){});

構造函數接受一個函數(executor)做爲參數,該函數在返回 Promise 實例以前被調用。函數的兩個參數分別是 resolve 和 reject 函數。es6

若是 executor 函數執行中拋出異常,則 Promise 視爲 rejected。數組

executor 函數返回值沒有意義。promise

類方法

Promise.all(iterable)

相似於 jQuery.when() 方法,只有 iterable 中全部的 Promise 都被 resolve,它返回一個新的被 resolve 的 Promise,resolved 值爲 iterable 中全部 resolved 值組成的數組;或者 iterable 中只要有一個 Promise 被 reject,則馬上返回一個新的被 reject 的 Promise,rejected 值同時傳遞給新的 Promise。瀏覽器

Promise.race(iterable)

一旦 iterable 中任何一個 Promise 被 resolve 或 reject,則當即返回一個新的被 resolve 或 reject 的 Promise。異步

Promise.reject(reason)

返回一個 rejected Promise。async

Promise.resolve(value)

返回一個新的 Promise。若是 value 是一個 thenable 對象(Promise),新 Promise 狀態與 thenable 一致;不然新 Promise 狀態爲 resolved,Promise 結果爲 value。函數

實例方法

Promise.prototype.catch(onRejected)

返回一個新的 Promise。Promise 將 rejected 值視爲一個 error,經過 catch 方法能夠捕捉 rejected 值,並將該值傳遞給 onRejected 函數。onRejected 函數返回值將做爲新 Promise 的 resolve 參數,也就是說,若是 onRejected 返回值是一個 Promise,則新 Promise 與該 Promise 狀態一致;不然新 Promise 狀態爲 resolved,結果值爲 onRejected 返回值。this

若是一個 rejected Promise 沒有調用過 catch 方法,在谷歌瀏覽器控制檯會輸出異常提示 Uncaught (in promise) 1prototype

Promise.prototype.then(onFulfilled, onRejected)

返回一個新 Promise。若是 onFulfilled 和 onRejected 是函數,則使用它們的返回值做爲新 Promise 的 resolve 參數。不然新 Promise 與舊 Promise 狀態保持一致。code

then 與 catch

雖然 then 方法能夠分別處理 resolution 和 rejection 兩種情景,但 ES6 Promise 將 rejection 更多地視做異步異常情景,所以提供 catch 方法處理 rejection 情景。

因此好的實踐是使用 then 方法處理 resolution,catch 方法處理 rejection。

// 不推薦
asyncRun().then(function(value) {}, function(error) {});

// 推薦
asyncRun().then(function(value){}).catch(function(rejected) {});

尤爲當須要連接多個 Promise 時,使用 then + catch 模式會讓代碼更加清晰。

// 不推薦
asyncRun()
    .then(function(value) {}, function(error) {})
    .then(function(value) {}, function(error) {})
    .then(function(value) {}, function(error) {});

// 推薦
asyncRun()
    .then(function(value){})        
    .then(function(value){})
    .then(function(value){})
    .catch(function(rejected) {});

Deferred 對象

ES6 取消了 Deferred 對象,鼓勵直接使用 Promise,並且主張 Promise 應該由它的建立者來 resolve 或 reject。

但某些場景下,Deferred 對象仍然是一種更好的選擇,尤爲是 Promise 建立者與求值者分屬不一樣對象時。

基於 ES6 Promise 實現的 Deferred 對象

簡潔版:

function Deferred() {
    var self = this;
    var promise = this.promise = new Promise(function(resolve, reject) {
        self.resolve = resolve;
        self.reject = reject;
    });
    this.then = this.promise.then.bind(promise);
    this.catch = this.promise.catch.bind(promise);
    this.catch(function() {});
}

完整版:

/*
 * @Author: laixi
 * @Date:   2016-11-18 11:40:06
 * @Last Modified by:   laixi
 * @Last Modified time: 2016-11-18 12:36:26
 */
var Deferred = function(beforeStart) {
  if (!(this instanceof Deferred)) {
    return new Deferred(beforeStart);
  }

  var _resolve;   // resolve function
  var _reject;  // reject function
  var _result;  // resolved value or rejected reason
  var _state = 'pending';   // promise status
  var doneCallbacks = [];
  var failCallbacks = [];
  var alwaysCallbacks = [];

  // create promise object
  var promise = new Promise(function(resolve, reject) {
    _resolve = resolve;
    _reject = reject;
  });

  // eliminate annoying error prompt at Chrome console
  promise.catch(function() {});
  
  // respectively call callbacks in done callback queue or fail callback queue
  promise.then(function(value) {
    _result = value;
    while (doneCallbacks.length > 0) {
      var callback = doneCallbacks.splice(0, 1)[0];
      callback.call(promise, value);
    }
  }, function(reason) {
    _result = reason;
    while (failCallbacks.length > 0) {
      var callback = failCallbacks.splice(0, 1)[0];
      callback.call(promise, reason);
    }
  });

  // extend promise by adding done, fail, always.
  // ----------------------------------------------

  promise.done = function(callback) {
    if (typeof callback === 'function') {
      if (_state === 'resolved') {
        callback.call(promise, _result);
      } else {
        doneCallbacks.push(callback);
      }
    }
    return promise;
  };

  promise.fail = function(callback) {
    if (typeof callback === 'function') {
      if (_state === 'rejected') {
        callback.call(promise, _result);
      } else {
        failCallbacks.push(callback);
      }
    }
    return promise;
  };

  promise.always = function(callback) {
    if (typeof callback === 'function') {
      if (_state === 'pending') {
        alwaysCallbacks.push(callback);
      } else {
        callback.call(promise, _result);
      }
    }
    return promise;
  };

  this.promise = function() {
    return promise;
  };

  this.state = function() {
    return _state;
  };

  this.resolve = function(value) {
    _state = 'resolved';
    _resolve.call(promise, value);
  };

  this.reject = function(reason) {
    _state = 'rejected';
    _reject.call(promise, reason);
  };

  this.catch = promise.catch.bind(promise);
  this.then = promise.then.bind(promise);
  this.done = promise.done.bind(promise);
  this.fail = promise.fail.bind(promise);
  this.always = promise.always.bind(promise);

  if (typeof beforeStart === 'function') {
    beforeStart.call(this, this);
  }
};
相關文章
相關標籤/搜索