本文是借鑑於ac黃的博客。javascript
接觸es6也有幾個月了,貌似沒有系統的去學習過它,老是用到什麼,查查什麼。今天就說下es6中的promise對象。前端
寫前端的同窗都常常遇到這種問題:在多個接口異步請求數據,而後利用這些數據來進行一系列的操做。通常以下實現:java
$.ajax({ url: '......', success: function (data) {
//基於data,才能進行下發操做 $.ajax({ url: '......', success: function (data) { // ...... } }); } });
這樣寫會致使兩個缺點:jquery
在須要多個操做的時候,會致使多個回調函數嵌套,致使代碼不夠直觀,就是常說的 Callback Hell。es6
若是幾個異步操做之間並無先後順序之分(例如不須要前一個請求的結果做爲後一個請求的參數)時,一樣須要等待上一個操做完成再實行下一個操做。ajax
es6中的Promise對象就來解決這個問題。api
何爲Promise對象?數組
一個 Promise 對象能夠理解爲一次將要執行的操做(經常被用於異步操做),使用了 Promise 對象以後能夠用一種鏈式調用的方式來組織代碼,讓代碼更加直觀(解決第1項缺點)。並且因爲 Promise.all
這樣的方法存在,可讓同時執行多個操做變得簡單(解決第2項缺點)。promise
你們能夠用把下方這段代碼貼到瀏覽器開發模式中的console中運行,看看結果。瀏覽器
function helloWorld (ready) { return new Promise(function (resolve, reject) { if (ready) { resolve("Hello World!"); } else { reject("Good bye!"); } }); } helloWorld(true).then(function (message) { alert(message); }, function (error) { alert(error); });
結果是,瀏覽器彈出 「hello world!」.
上面的代碼實現的功能很是簡單,helloWord
函數接受一個參數,若是爲 true
就打印 "Hello World!",若是爲 false
就打印錯誤的信息。helloWord
函數返回的是一個 Promise 對象。
在 Promise 對象當中有兩個重要方法————resolve
和 reject
。
resolve
方法可使 Promise 對象的狀態改變成成功,同時傳遞一個參數用於後續成功後的操做,在這個例子當中就是 Hello World! 字符串。
reject
方法則是將 Promise 對象的狀態改變爲失敗,同時將錯誤的信息傳遞到後續錯誤處理的操做。
Fulfilled 能夠理解爲成功的狀態
Rejected 能夠理解爲失敗的狀態
Pending 既不是 Fulfilld 也不是 Rejected 的狀態,能夠理解爲 Promise 對象實例建立時候的初始狀態
helloWorld 的例子中的 then
方法就是根據 Promise 對象的狀態來肯定執行的操做,resolve 時執行第一個函數(onFulfilled),reject 時執行第二個函數(onRejected)。
helloWorld 的例子當中利用了 then(onFulfilld, onRejected)
方法來執行一個任務打印 "Hello World!",在多個任務的狀況下 then
方法一樣能夠用一個清晰的方式完成。
例如:
function printHello (ready) { return new Promise(function (resolve, reject) { if (ready) { resolve("Hello"); } else { reject("Good bye!"); } }); } function printWorld () { alert("World"); } function printExclamation () { alert("!"); } printHello(true) .then(function(message){ alert(message); }) .then(printWorld) .then(printExclamation);
結果是順序彈出:「Hello」「World」「!」
then
可使用鏈式調用的寫法緣由在於,每一次執行該方法時老是會返回一個 Promise 對象。另外,在 then
onFulfilled 的函數當中的返回值,能夠做爲後續操做的參數。所以上面的方法能夠寫爲:
function printHello (ready) { return new Promise(function (resolve, reject) { if (ready) { resolve("Hello"); } else { reject("Good bye!"); } }); } printHello(true).then(function (message) { return message; }).then(function (message) { return message + ' World'; }).then(function (message) { return message + '!'; }).then(function (message) { alert(message); });
結果輸出是:「Hello World!」。
catch
方法是 then(onFulfilled, onRejected)
方法當中 onRejected
函數的一個簡單的寫法,也就是說能夠寫成 then(fn).catch(fn)
,至關於 then(fn).then(null, fn)
。使用 catch
的寫法比通常的寫法更加清晰明確。
Promise.all
能夠接收一個元素爲 Promise 對象的數組做爲參數,當這個數組裏面全部的 Promise 對象都變爲 resolve 時,該方法纔會返回。
var p1 = new Promise(function (resolve) { setTimeout(function () { resolve("Hello"); }, 3000); }); var p2 = new Promise(function (resolve) { setTimeout(function () { resolve("World"); }, 1000); }); Promise.all([p1, p2]).then(function (result) { console.log(result); // ["Hello", "World"] });
上面的例子模擬了傳輸兩個數據須要不一樣的時長,雖然 p2 的速度比 p1 要快,可是 Promise.all
方法會按照數組裏面的順序將結果返回。
平常開發中常常會遇到這樣的需求,在不一樣的接口請求數據而後拼合成本身所需的數據,一般這些接口之間沒有關聯(例如不須要前一個接口的數據做爲後一個接口的參數),這個時候 Promise.all
方法就能夠派上用場了。
Promise.race 和 Promise.all 方法相似,它一樣接收一個數組,不一樣的是隻要該數組中的 Promise 對象的狀態發生變化(不管是 resolve 仍是 reject)該方法都會返回。
在瀏覽器端,一些主流的瀏覽器都已經可使用 Promise 對象進行開發,在 Node.js 配合 babel 也能夠很方便地使用。
若是要兼容舊的瀏覽器,建議能夠尋找一些第三方的解決方案,例如 jQuery 的 $.Deferred。