這篇文章面向對Promise不甚瞭解的朋友,我將告訴你如何把它快速運用在開發中。
什麼是Promise?
簡單幾句介紹一下。Promise是抽象非同步處理物件以及對其進行各種操作的元件。你可以理解為:它的出現,是為了讓我們更方便的進行非同步處理。
在Promise出現之前,說到JavaScript的非同步處理,我們都會想到回撥函式,like this:
getAsync("fileA.txt", function(error, result){
if(error){// 取得失敗時的處理 throw error;
throw error;
}
});複製程式碼
上面遵循Node.js
的規定,回撥的第一個引數是error
。如果所有的回撥函式都像Node.js
一樣,統一引數使用規則的話,那寫法會很明瞭,但也僅僅是編碼規範而已,使用不同的寫法也不會出錯。
而Promise則是把非同步處理物件和處理規則進行規範化,並採用統一的介面來編寫,使用規定方法之外的寫法都會出錯。
我們可以先看一個簡單的使用Promise進行非同步處理的例子:
var promise = getAsyncPromise("fileA.txt");
promise.then(function(result){
// 獲取檔案內容成功時的處理
}).catch(function(error){
// 獲取檔案內容失敗時的處理
});複製程式碼
看上去和回撥函式有些不一樣,在使用Promise進行非同步處理的時候,我們必須按照介面規定的方法編寫處理程式碼。
也即是說,除了使用Promise規定的方法(上面的then
和catch
),其他的方法都是不能使用的,而回撥函式可以自定義回撥的引數。
所以,Promise可以將複雜的非同步處理輕鬆的進行模式化,沒有理由讓你不使用它。
接下來,我們看看怎麼把Promise運用到開發中,這個才是大家想了解的。
學習Promise
在運用到開發之前,我們有必要先學習一些Promise的基本API(暫時看的有點糊塗沒關係,等會的例子實踐會和大家講清楚的)。
目前大致有下面三種型別:
1.Constructor(構造器)
我們從建構函式Promise
來建立一個新promise
物件作為介面。
要建立一個promise
物件,可以使用new
來呼叫Promise
構造器來進行例項化。
var promise = new Promise(function(resolve, reject) { // 非同步處理
// 處理結束後、呼叫resolve 或 reject
});複製程式碼
2.Instance Method(例項方法)
在通過new
生成的promise
物件時,我們設定了在resolve(成功)和reject(失敗)時呼叫的回撥函式,我們可以使用promise.then()
例項方法。
promise.then(onFulfilled,onReject);複製程式碼
resolve(成功)時:
onFulfilled
會被呼叫reject(失敗)時:
onReject
會被呼叫
onFulfilled
和onReject
都為可選引數
promise.then
成功和失敗時都可以使用,另外在異常處理時,可以使用promise.then(undefined, onReject)
這種方式,只指定reject
時的回撥函式即可。不過這種情況下,使用promise.catch()
是個明智之選。
promise.catch(onReject);複製程式碼
3.Static Method(靜態方法)
像promise.all()
和Promise.resolve()
等在內,主要都是一些輔助方法(可以理解為一些語法糖),這裡不作深入探討。
運用在開發中
我們先來看一段Promise使用流程程式碼:
function asyncFunction() { //(1)
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('Async Hello World');
}, 300);
});
}
asyncFunction().then(function(value) { //(2)
console.log(value); //300ms後列印 "Async Hello World"
}).catch(function(error) { //(3)
console.log(error);
})複製程式碼
分析一下上面程式碼。
執行(1)
處函式,會返回一個Promise物件,Promise物件內部在300ms後執行resolve()
方法,這個方法呼叫(2)
處的then()
方法,並傳入引數,如果Promise物件內部出現任何錯誤(比如平臺不支援setTimeout方法),就會執行(3)
處的catch()
發放,並把錯誤作為引數傳入。
這裡提一下,我看到很多朋友把Promise理解為Ajax的一種擴充套件,其實並不是這樣的,Ajax只是一種請求資料的方式,因為Ajax是非同步的,所以我們可以用Promise去管理Ajax請求,但這並不意味這Promise只服務於Ajax,只要是非同步處理,我們都可以使用Promise去處理,就比如上面的
setTimeout
。
看到這裡大家對Promise應該有一個大概的認識了,實際開發中Promise大部分時間還是搭配Ajax使用,我們來看看應該怎麼做,下面用原生的方式請求Ajax,大家也溫習一下:
function getURL(URL) {
return new Promise(function(resolve, reject) {
var req = new XMLHttpRequest();
req.open('GET', URL, true);
req.onload = function() {
if (req.status === 200) {
resolve(req.responseText);
}else {
reject(new Error(req.statusText));
}
};
req.onerror = function() {
reject.(new Error(req.statusText));
};
req.send();
});
}
// 執行示例
var URL = "https://rockjins.js.org";
getURL(URL).then(function onFulfilled(value){
console.log(value);
}).catch(function onRejected(error){
console.error(error);
});複製程式碼
getURL
只有在XHR取得狀態為200時才會呼叫resolve
,也就是資料取得成功時,而其他情況(資料取得失敗)則會呼叫reject
。
當呼叫resolve(req.responseText)
時,then
方法也會被呼叫,並接收到req.responseText
引數。
熟悉Node.js的朋友在寫回撥時會會將callback(error,response)
的第一個引數設為error
物件,在Promise中,resolve(成功)/reject(失敗)擔當了這個職責。
XHR中onerror
觸發時,就是發生錯誤時,理所當然要呼叫reject
,我們重點來看下傳給reject
的值。
發生錯誤時要像這樣reject(new Error(req.statusText))
,建立一個Error物件再講具體的值傳入進去。傳給reject
的值也沒有什麼特殊限制,一般只要是Error物件(或繼承自Error物件)即可。
小結
其實你理解了Promise的運作流程,使用它十分方便和簡單,它就是一個非同步管理器,幫助我們更好地去進行非同步處理。
試想,如果Promise真的很複雜,那它出現的意義是什麼?本末倒置了,哈哈。
喜歡本文的朋友可以關注我的微信公眾號,不定期推送一些好文。
本文出自Rockjins Blog,轉載請與作者聯絡。否則將追究法律責任。