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就是三個狀態。利用觀察者模式的編程思想,只須要經過特定書寫方式註冊對應狀態的事件處理函數,而後更新狀態,調用註冊過的處理函數便可。 異步
這個特定方式就是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裏面的回調函數。動畫