Promise 對象用來進行延遲(deferred) 和 異步(asynchronous) 計算。html
一個 Promise 處於如下三種狀態之一:html5
Promise 接口表示爲一個值的代理,這個值在promise建立時未必已知. 它容許你將 handlers 與一個異步 action 最終的成功或失敗狀態關聯起來. 這使得異步方法能夠像同步方法那樣返回值: 異步方法返回一個在將來某個時刻擁有一個值的 promise 來替代最終返回值.node
pending狀態的promise既可帶着一個值成爲 fulfilled 狀態,也可帶着一個reason成爲 rejected 狀態. 任意狀況發生時, 經過promise的 then 方法所排列(queued up)的相應handlers 就會被調用. (當綁定相應的 handler 時,若是 promise 已經處於 fulfilled 或 rejected 狀態這個 handler 將會被調用, 因此在異步操做的完成和它的 handler 的綁定之間不存在競爭條件.)jquery
由於 Promise.prototype.then 和 Promise.prototype.catch 方法返回 promises, 因此它們能夠被鏈式調用—一種被稱爲 composition 的操做.git
簡單的說,Promise 被當成 callback hell 的救命仙丹。es6
回調函數是JavaScript的一大特點! node.js官方的api基本都是以會回調方式傳遞函數返回值。習慣同步編程的對這種異步方式多少會產生水土不服,並且層層嵌套,不知不覺就建造起了一座高高的回調金字塔。針對這種廣泛問題,Promise應勢而生!github
建立 Promise編程
var promise = new Promise(function(resolve, reject) { // 作一些異步操做的事情,而後…… if (/* 一切正常 */) { resolve("Stuff worked!"); } else { reject(Error("It broke")); } });
Promise 的構造器接受一個函數做爲參數,它會傳遞給這個回調函數兩個變量 resolve 和 reject。在回調函數中作一些異步操做,成功以後調用 resolve,不然調用 reject。json
調用 reject 的時候傳遞給它一個 Error 對象只是個慣例並不是必須,這和經典 JavaScript 中的 throw 同樣。傳遞 Error 對象的好處是它包含了調用堆棧,在調試的時候會有點用處。windows
使用 Promise:
promise.then(function(result) { console.log(result); // 「完美!」 }, function(err) { console.log(err); // Error: "出問題了" });
「then」接受兩個參數,成功的時候調用一個,失敗的時候調用另外一個,兩個都是可選的,因此你能夠只處理成功的狀況或者失敗的狀況。
你能夠對結果作些修改而後返回一個新值:
var promise = new Promise(function(resolve, reject) { resolve(1); }); promise.then(function(val) { console.log(val); // 1 return val + 2; }).then(function(val) { console.log(val); // 3 });
你也能夠把「then」串聯起來依次執行異步操做。
當你從「then」的回調函數返回的時候,這裏有點小魔法。若是你返回一個值,它就會被傳給下一個「then」的回調;而若是你返回一個「類 Promise」的對象,則下一個「then」就會等待這個 Promise 明確結束(成功/失敗)纔會執行。例如:
你也能夠把「then」串聯起來依次執行異步操做。
當你從「then」的回調函數返回的時候,這裏有點小魔法。若是你返回一個值,它就會被傳給下一個「then」的回調;而若是你返回一個「類 Promise」的對象,則下一個「then」就會等待這個 Promise 明確結束(成功/失敗)纔會執行。例如:
返回一個值
getJSON('story.json').then(function(story) { return getJSON(story.chapterUrls[0]); }).then(function(chapter1) { console.log("Got chapter 1!", chapter1); });
你返回一個「類 Promise」的對象
var storyPromise; function getChapter(i) { storyPromise = storyPromise || getJSON('story.json'); return storyPromise.then(function(story) { return getJSON(story.chapterUrls[i]); }) } // 用起來很是簡單: getChapter(0).then(function(chapter) { console.log(chapter); return getChapter(1); }).then(function(chapter) { console.log(chapter); });
前面已經看到,「then」接受兩個參數,一個處理成功,一個處理失敗(或者說確定和否認,按 Promise 術語):
get('story.json').then(function(response) { console.log("Success!", response); }, function(error) { console.log("Failed!", error); });
你還可使用「catch」:
get('story.json').then(function(response) { console.log("Success!", response); }).catch(function(error) { console.log("Failed!", error); });
Promise 被否認以後會跳轉到以後第一個配置了否認回調的 then(或 catch,同樣的)。對於 then(func1, func2) 來講,必會調用 func1 或 func2 之一,但毫不會兩個都調用。而 then(func1).catch(func2) 這樣,若是 func1 返回否認的話 func2 也會被調用,由於他們是鏈式調用中獨立的兩個步驟。看下面這段代碼:
asyncThing1().then(function() { return asyncThing2(); }).then(function() { return asyncThing3(); }).catch(function(err) { return asyncRecovery1(); }).then(function() { return asyncThing4(); }, function(err) { return asyncRecovery2(); }).catch(function(err) { console.log("Don't worry about it"); }).then(function() { console.log("All done!"); });
靜態方法
Promise.resolve(promise);
返回一個 Promise(當且僅當 promise.constructor == Promise)
Promise.resolve(thenable);
從 thenable 對象建立一個新的 Promise。一個 thenable(類 Promise)對象是一個帶有「then」方法的對象。
Promise.resolve(obj);
建立一個以 obj 爲確定結果的 Promise。
Promise.reject(obj);
建立一個以 obj 爲否認結果的 Promise。爲了一致性和調試便利(如堆棧追蹤),obj 應該是一個 Error 實例對象。
Promise.all(array);
建立一個 Promise,當且僅當傳入數組中的全部 Promise 都確定以後才確定,若是遇到數組中的任何一個 Promise 以否認結束,則拋出否認結果。每一個數組元素都會首先通過 Promise.resolve,因此數組能夠包含類 Promise 對象或者其餘對象。確定結果是一個數組,包含傳入數組中每一個 Promise 的確定結果(且保持順序);否認結果是傳入數組中第一個遇到的否認結果。
Promise.race(array);
建立一個 Promise,當數組中的任意對象確定時將其結果做爲確定結束,或者當數組中任意對象否認時將其結果做爲否認結束。
其實已經有一些第三方庫實現了 Promise 的功能:
上面這些庫和 JavaScript 原生 Promise 都遵照一個通用的、標準化的規範:Promises/A+,jQuery 有個相似的方法叫 Deferred,但不兼容 Promises/A+ 規範,因而會有點小問題,使用需謹慎。jQuery 還有一個 Promise 類型,它實際上是 Deferred 的縮減版,因此也有一樣問題。
目前的瀏覽器已經(部分)實現了 Promise。
Chrome 3二、Opera 19 和 Firefox 29 以上的版本已經默認支持 Promise。因爲是在 WebKit 內核中因此咱們有理由期待下個版本的 Safari 也會支持,而且 IE 也在不斷的開發中。
要在這兩個瀏覽器上達到兼容標準 Promise,或者在其餘瀏覽器以及 Node.js 中使用 Promise,能夠看看這個 polyfill(gzip 以後 2K)。