Promise是異步編程的一種解決方案,比起傳統的解決方案(回調函數和事件),它顯得更加的強大和方便(具體請看下文)。從語法上來說,Promise是一個對象,從它能夠獲取異步操做的消息。Promise對象提供統一的API,各類異步操做均可以用一樣的方法進行處理。node
你們一致會回答,解決回調地獄。那什麼又是回調地獄?它有什麼缺點?es6
若是要執行四個步驟,依次執行,那麼傳統咱們可能會這麼作:ajax
step1(function (value1) {
step2(value1, function(value2) {
step3(value2, function(value3) {
step4(value3, function(value4) {
// Do something with value4
});
});
});
});
複製代碼
爲了解決這種看起來不很舒服,寫起來更不舒服的寫法,咱們可能會想起鏈式寫法:編程
var obj = {
stepOne: function () {
console.log('one');
return this;
},
stepTwo: function () {
console.log('two');
return this;
},
stepThree: function () {
console.log('three');
return this;
}
}
obj.stepOne().stepThree().stepTwo();
複製代碼
這種寫法的核心在於,每次都返回this。 這樣的好處在於:json
那若是咱們還須要一些其餘需求的時候呢?好比:數組
這個時候,就須要用到咱們強大的Promise了promise
先來看看怎麼使用吧!直接上代碼:bash
const p1 = new Promise(function(resolve, reject) {
// 在這裏作一些邏輯處理
// 若是異步操做成功的時候,調用resolve
if (true) {
resolve('success');
} else {
// 操做失敗後咱們就調用reject()
reject('fail');
}
})
p1.then((val) => {
console.log(val); // success
}, (err) => {
console.log(err)
})
複製代碼
咱們能夠看到Promise是一個構造函數,用來生成Promise實例,它接收一個函數做爲參數,這個函數有兩個參數——resolve和reject(它們也是兩個函數,已經由JavaScript引擎提供,不用本身部署)。異步
咱們常常會在這個函數裏處理一些邏輯,若是處理成功後咱們會執行resolve(將狀態從「未完成」轉爲「完成」),失敗後執行reject(將狀態從「未完成」轉換爲「失敗」)。異步編程
三個狀態
實例生成以後,咱們可使用then方法指定resolved和rejected狀態的回調函數。像上面的代碼,就至關於執行第一個回調函數,第二個不會執行(這個時候其實不提供第二個參數也是能夠的)。
若是是執行失敗,狀態變成reject的時候,就會執行第二個回調函數,就會輸出'fail'。可是其實咱們不是很推薦這樣的寫法,咱們能夠將第二個回調函數寫catch方法的形式。
const p1 = new Promise(function(resolve, reject) {
// 在這裏作一些邏輯處理
// 若是異步操做成功的時候,調用resolve
if (false) {
resolve('success');
} else {
// 操做失敗後咱們就調用reject()
reject('fail');
}
})
p1.then((val) => {
console.log(val);
}).catch((err) => {
console.log(err); // fail
})
複製代碼
這種寫法相似於try...catch...,更加易於咱們理解。這個時候咱們其實就已經解決了出錯咱們可以捕捉的問題了。
採用鏈式的then,能夠指定一組按照次序調用的回調函數。這個時候前面的一個返回的多是另一個Promise對象(也就是說有異步操做)。這樣後面的這個Promise就依賴於前面Promise對象的狀態。
const p1 = new Promise(function(resolve, reject) {
console.log(1);
setTimeout(function() {
console.log(2);
resolve();
}, 1000);
})
const p2 = new Promise(function(resolve, reject) {
console.log(3);
resolve(p1);
})
p2.then(() => {
console.log(4);
}).then(() => {
console.log(5);
})
複製代碼
以上代碼,咱們應該注意一點p2的resolve方法將p1做爲參數,也就是說p2的執行依賴於p1的執行。當p2準備好的時候,p1可能還沒準備好,這個時候p2就得等p1。
另外,須要注意的一點就是,then方法返回的是一個新的Promise實例(注意,不是以前的Promise實例),所以能夠採用鏈式寫法,即then方法以後再調用另外一個then方法。這樣,咱們就能夠實現了上面的需求了!
下面簡單介紹一下Promise對象的幾個方法,咱們常常也會用到。
Promise.all()
直接上代碼:
const p = Promise.all([p1, p2, p3]);
複製代碼
Promise.all方法接收一個數組做爲參數,p一、p二、p3都是Promise實例。這個時候p的狀態由p一、p二、p3。它們的依賴機制相似於電路中的串聯,如今咱們使用三條線(就是p一、p二、p3)進行串聯,p就是最後燈泡,燈泡要亮的話,三個都要成功,只要其中的一個沒有成功,那麼p的狀態就是rejected。
Promise.race()
const p = Promise.race([p1, p2, p3]);
複製代碼
這個方法也是接受一個數組做爲參數。race的英文意思就有競賽的意思。上面的代碼中表示,p一、p二、p3中哪一個勝出(最新狀態發生改變,無論是失敗仍是成功),那麼p的狀態就會跟着它改變。
Promise.resolve()
做用:將現有對象轉換成Promise對象,這樣咱們就能夠調用then方法等
const jsPromise = Promise.resolve($.ajax('/whatever.json'));
複製代碼
Promise.reject()
Promise.reject(reason)方法也會返回一個Promise實例,該實例狀態爲rejected。
const p = Promise.reject('出錯了');
// 等同於
const p = new Promise((resolve, reject) => reject('出錯了'))
p.then(null, function (s) {
console.log(s)
});
// 出錯了
複製代碼
參考: https://cnodejs.org/topic/560dbc826a1ed28204a1e7de
http://es6.ruanyifeng.com/#docs/promise