快速將 Promise 運用在開發中
這篇文章面向對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真的很復雜,那它出現的意義是什么?本末倒置了,哈哈。
來自:https://juejin.im/post/58c5a621570c35006d66eee9