Promise原理

簡介

Promise 對象用於延遲(deferred) 計算和異步(asynchronous )計算。一個Promise對象表明着一個還未完成,但預期未來會完成的操做。Promise 對象是一個返回值的代理,這個返回值在promise對象建立時未必已知。它容許你爲異步操做的成功或失敗指定處理方法。 這使得異步方法能夠像同步方法那樣返回值:異步方法會返回一個包含了原返回值的 promise 對象來替代原返回值。javascript

解決了什麼問題及怎麼使用

// 一個簡單的示例 執行一個動畫A,執行完以後再去執行另外一個動畫B
setTimeout(function(){
    //A動畫
    console.log('A');
    setTimeout(function() {
        //B動畫
        console.log('B');
    },300)
},300);
// 這裏只有兩個動畫,若是有更多呢,就會看到一堆函數縮進

不難想象,若是依次有不少個動畫,就會出現多重嵌套。代碼不是縱向發展,而是橫向發展,很快就會亂成一團,沒法管理。java

由於多個異步操做造成了強耦合,只要有一個操做須要修改,它的上層回調函數和下層回調函數,可能都要跟着修改。這種狀況就稱爲回調函數地獄「(callback hell)編程

Promise 對象就是爲了解決這個問題而提出的。它不是新的語法功能,而是一種新的寫法,容許將回調函數的嵌套,改爲鏈式調用。 promise

瀏覽器實現方式:能夠在支持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);
});

promise會讓代碼變得更容易維護,像寫同步代碼同樣寫異步代碼。app

promise原理

其實,promise就是三個狀態。利用觀察者模式的編程思想,只須要經過特定書寫方式註冊對應狀態的事件處理函數,而後更新狀態,調用註冊過的處理函數便可。 異步

這個特定方式就是then,done,fail,always…等方法,更新狀態就是resolve、reject方法。async

/**
 * Promise類實現原理
 * 構造函數傳入一個function,有兩個參數,resolve:成功回調; reject:失敗回調
 * state: 狀態存儲 [PENDING-進行中 RESOLVED-成功 REJECTED-失敗]
 * doneList: 成功處理函數列表
 * failList: 失敗處理函數列表
 * done: 註冊成功處理函數
 * fail: 註冊失敗處理函數
 * then: 同時註冊成功和失敗處理函數
 * always: 一個處理函數註冊到成功和失敗
 * resolve: 更新state爲:RESOLVED,而且執行成功處理隊列
 * reject: 更新state爲:REJECTED,而且執行失敗處理隊列
**/

class PromiseNew {
  constructor(fn) {
    this.state = 'PENDING';
    this.doneList = [];
    this.failList = [];
    fn(this.resolve.bind(this), this.reject.bind(this));
  }

  // 註冊成功處理函數
  done(handle) {
    if (typeof handle === 'function') {
      this.doneList.push(handle);
    } else {
      throw new Error('缺乏回調函數');
    }
    return this;
  }

  // 註冊失敗處理函數
  fail(handle) {
    if (typeof handle === 'function') {
      this.failList.push(handle);
    } else {
      throw new Error('缺乏回調函數');
    }
    return this;
  }

  // 同時註冊成功和失敗處理函數
  then(success, fail) {
    this.done(success || function () { }).fail(fail || function () { });
    return this;
  }

  // 一個處理函數註冊到成功和失敗
  always(handle) {
    this.done(handle || function () { }).fail(handle || function () { });
    return this;
  }

  // 更新state爲:RESOLVED,而且執行成功處理隊列
  resolve() {
    this.state = 'RESOLVED';
    let args = Array.prototype.slice.call(arguments);
    setTimeout(function () {
      this.doneList.forEach((item, key, arr) => {
        item.apply(null, args);
        arr.shift();
      });
    }.bind(this), 200);
  }

  // 更新state爲:REJECTED,而且執行失敗處理隊列
  reject() {
    this.state = 'REJECTED';
    let args = Array.prototype.slice.call(arguments);
    setTimeout(function () {
      this.failList.forEach((item, key, arr) => {
        item.apply(null, args);
        arr.shift();
      });
    }.bind(this), 200);
  }
}

// 下面一波騷操做
new PromiseNew((resolve, reject) => {
  resolve('hello world');
  // reject('you are err');
}).done((res) => {
  console.log(res);
}).fail((res) => {
  console.log(res);
})

解釋:當咱們調用new Promise(fn)時,就會當即執行第一個參數fn。上面案例中,先將then(done,fail)對應的回調函數分別加入到doneList或者failList中,always中對應的參數同時加到doneList和failList中;函數

當異步代碼執行完畢,就調用resolve方法,此時改變promise的狀態爲resolved,並執行doneList裏面的回調函數。若是執行失敗,則調用fail方法,此時改變promise的狀態爲rejected,並執行failList裏面的回調函數。動畫

相關文章
相關標籤/搜索