Promise原理淺析

jopen 9年前發布 | 29K 次閱讀 Promise

 

Promise介紹

項目相關demo和代碼地址

介紹

Promise 對象用于延遲(deferred) 計算和異步(asynchronous ) 計算.。一個Promise對象代表著一個還未完成,但預期將來會完成的操作。 Promise 對象是一個返回值的代理,這個返回值在promise對象創建時未必已知。它允許你為異步操作的成功或失敗指定處理方法。 這使得異步方法可以像同步方法那樣返回值:異步方法會返回一個包含了原返回值的 promise 對象來替代原返回值。

引自 MDN

</div>

它解決什么問題

一個簡單的示例 執行一個動畫A,執行完之后再去執行另一個動畫B

   setTimeout(function(){
  //A動畫
  console.log('A');
  setTimeout(function() {
      //B動畫
      console.log('B');
  },300)
    },300);

這里只有兩個動畫,如果有更多呢,就會看到一堆函數縮進

一種寫法

瀏覽器實現方式 可以在支持Promise的版本上運行

var p = new Promise(function(resolve, reject){
  setTimeout(function(){
    //A動畫
    console.log('A');
    resolve();
  },300);
});

p.then(function(){ setTimeout(function() { //B動畫 console.log('B'); },300); });</pre>

另一種寫法(jQuery版本)

jQuery版本的實現

var deferred = $.Deferred();
setTimeout(function(){
  //A動畫
  console.log('A');
  deferred.resolve();
},300);

deferred.done(function() { setTimeout(function() { //B動畫 console.log('B'); },300) });</pre>

好像從代碼上來看,是多了幾行的樣子,但是能用這種串行的方式來寫,感覺一定很爽吧

Promise中的概念

Promise中有幾個狀態:

  • pending: 初始狀態, 非 fulfilled 或 rejected.
  • fulfilled: 成功的操作.
  • rejected: 失敗的操作.

這里從pending狀態可以切換到fulfill狀態(jQuery中是resolve狀態),也可以從pengding切換到reject狀態,這個狀態切換不可逆,且fulfilled和reject兩個狀態之間是不能互相切換的。

Promise原理淺析

一個簡單版本的實現

/**
 * simple promise 
 * @param {[type]} fun [description]
 */
function PromiseB(fun) {
  this.succArg = undefined;
  this.failArg = undefined;
  this.succCbs = [];
  this.failCbs = [];
  this._status = this.STATUS.PENDING;
  this._execFun(fun);
}
PromiseB.prototype.STATUS = {
  PENDING: 1, //掛起狀態
  RESOLVE: 2, //完成狀態
  REJECT: 3 //拒絕狀態
};
PromiseB.prototype._isFunction = function(f) {
  return Object.prototype.toString.call(f) === '[object Function]';
};
PromiseB.prototype._exec = function(callback, arg) {
  var newcallback;
  if (this._isFunction(callback)) {
    if (callback instanceof PromiseB) {
      callback.resolve(arg);
    } else {
      newcallback = new PromiseB(callback);
      newcallback.resolve(arg);
    }
  }
};
PromiseB.prototype._execFun = function(fun) {
  var that = this;
  if (this._isFunction(fun)) {
    fun(function() {
      that.succArg = Array.prototype.slice.apply(arguments);
      that._status = that.STATUS.RESOLVE;
      that.resolve.apply(that, arguments);
    }, function() {
      that.failArg = Array.prototype.slice.apply(arguments);
      that._status = that.STATUS.REJECT;
      that.reject.apply(that, arguments);
    });
  } else {
    this.resolve(fun);
  }
};
PromiseB.prototype.resolve = function() {
  var arg = arguments,
    ret,
    callback = this.succCbs.shift();
  if (this._status === this.STATUS.RESOLVE && callback) {
    ret = callback.apply(callback, arg);
    if (!(ret instanceof PromiseB)) {
      var _ret = ret;
      ret = new PromiseB(function(resolve) {
        setTimeout(function() {
          resolve(_ret);
        });
      });
      ret.succCbs = this.succCbs.slice();
    }
    // this._exec(callback.apply(callback, arg), arg);
  }
};
PromiseB.prototype.reject = function() {
  var arg = arguments,
    ret,
    callback = this.failCbs.shift();
  if (this._status === this.STATUS.REJECT && callback) {
    ret = callback.apply(callback, arg);
    if (!(ret instanceof PromiseB)) {
      var _ret = ret;
      ret = new PromiseB(function(resolve) {
        setTimeout(function() {
          resolve(_ret);
        }, 200);
      });
      ret.failCbs = this.failCbs.slice();
    }
  }
};
PromiseB.prototype.then = function(s, f) {
  this.done(s);
  this.fail(f);
  return this;
};
PromiseB.prototype.done = function(fun) {
  if (this._isFunction(fun)) {
    if (this._status === this.STATUS.RESOLVE) {
      fun.apply(fun, this.succArg);
    } else {
      this.succCbs.push(fun);
    }
  }
  return this;
};
PromiseB.prototype.fail = function(fun) {
  if (this._isFunction(fun)) {
    if (this._status === this.STATUS.REJECT) {
      fun.apply(fun, this.failArg);
    } else {
      this.failCbs.push(fun);
    }
  }
  return this;
};
PromiseB.prototype.always = function(fun) {
  this.done(fun);
  this.fail(fun);
  return this;
};

總結

  • promise會讓代碼變得更容易維護,像寫同步代碼一樣寫異步代碼
  • 了解promise的原理,寫個簡單的實現版本就好了
  • promise的實現方案有很多,可以看 這里
 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!