隨便查查網上的 Promise 教程,多到數不勝數,然而我仍是沒有準確理解什麼是 Promise 以及它的使用場景。因此打算本身寫一下學習心得,用來查漏補缺。目標是寫的簡單直白,便於之後查閱反思。es6
「Promise 是一個對象。」 對於這種解釋,我不是很滿意,畢竟在 JS 的世界中,萬物皆可對象(這句話也是流傳已久的bug,想知道具體的緣由,請查閱 null 相關的知識)。咱們經過 typeof Promise
能夠獲得 function
。這進一步說明,Promise 更是一個函數。同時來複習一下:JS 中,函數是一種特殊的對象,MDN 中也叫作頭等對象(first-class)。因此,請不要簡單解釋爲 Promise 是一個對象,這有點偷懶。ajax
那麼在認識到 Promise 是一個函數後,這個函數的本質,又是什麼?答案是:構造函數。爲何這樣理解?由於咱們在使用 Promise 的時候,永遠是 new Promise()
開始的。既然是構造函數,當咱們建立一個 Promise 實例的時候,這個實例對象都有什麼內容?來看看下面的代碼:promise
var p = new Promise(function(resolve, reject){});
consoel.log(p);
// __proto__: Promise
// [[PromiseStatus]]: "pending"
// [[PromiseValue]]: undefined
console.log(p.__proto__)
// Promise {constructor: ƒ, then: ƒ, catch: ƒ, finally: ƒ, Symbol(Symbol.toStringTag): "Promise"}
複製代碼
咱們獲得的對象 p 上,這個對象也比較簡單,一共只有三個東西:proto,PromiseStatus,PromiseValue。這三個值。__proto__
上則存在咱們熟悉的 then
等方法,這就是鏈式調用的原理——經過返回 Promise 對象,調用其原型鏈上的方法實現。其他兩個是內部變量,一個是記錄內部狀態,另外一個記錄了返回值。bash
Promise 的狀態有三種:異步
PromiseValue 記錄的返回值也很簡單。若是一個 promise 的狀態是完成(resolved)那麼,返回值就是 then(res => return res;)
裏的 res
;若是是拒絕狀態,那麼則是 .catch()
裏面的。值得一提的是,Promise 實例中的狀態,永遠是肯定的,並且不可逆,也就是說一個已經 resolved 或者 rejected 的promise,不能轉化成 pending。async
以前咱們說到 Promise 是一個構造函數,是從 Promise 的類型來看問題。若是從應用層面來看待,那麼 Promise 則是一套異步操做的處理機制。這種機制十分擅長解決回調地獄。來寫一個在 jQuery 時代不可避免的回調場景:函數
$.ajax({
success: function(res) {
if(res) {
callAnotherFun(function(res) {
$.ajax({
success: secondResponse
})
});
}
}
})
複製代碼
改寫成 Promise學習
function fetch() {
return new Promise(function(resolve) {
$.ajax({
success: function(res) {
resolve(res);
}
})
});
}
fetch().then(res => {
return callAnotherFun(function(res) {
return fetch()
})
}).then(res => {
secondResponse(res)
})
複製代碼
從上面的改寫能夠看出 Promise 將多層函數回調的嵌套fetch
function a() {
b(function () {
c(function() {
d(function() {
...
})
})
})
}
複製代碼
改寫成了優化
myPromise().then(res => {
a();
return myPromise();
}).then(res => {
b();
return myPromise();
}).then(res => {
c();
return myPromise();
}).then(red => {
d();
})
複製代碼
這種寫法,統一了異步處理的風格,已經寫入 ES6 的標準之中。其實關於這樣的鏈式調用,咱們仍然有優化的空間,這個優化操做就引入下面要講的 async/await
的相關內容。
async函數返回一個 Promise 對象,可使用then方法添加回調函數。當函數執行的時候,一旦遇到await就會先返回,等到異步操做完成,再接着執行函數體內後面的語句。
咱們能夠將上一節的代碼改寫成 async/await 的形式,以下:
async function myPromise() { }
async function main() {
await myPromise(function() {a () });
await myPromise(function() {b () });
await myPromise(function() {c () });
await myPromise(function() {d () });
}
main();
複製代碼
從上圖能夠看出,async 提供了一種像同步風格同樣來編寫異步過程的代碼的方式。這裏要注意的是 await
必定是寫在 async
裏面的。顧名思義它是 async wait
異步等待的意思。
那麼結合到具體業務,咱們應該如何使用。常見的異步場景有:
等等…… 下面我從一個小栗子來簡單應用下,感覺 Promise 和 async 結合的代碼的可讀性。