一、前言概述
在前端開發中,相信很多讀者都使用過AJAX,這種比較? 逼的非同步處理方式,確實在一定程度上方便和簡化了我們的某些需求,但有時候也會遇到在一個操作中,會需要多個非同步請求的情況,在以往的處理中,比如筆者就曾做過2個及多個AJAX層層巢狀著處理的方式,這種方式,在當時看上去也可以滿足一般的需求,但看著彆扭,總覺得哪裡不爽;
$.ajax({
cache: false,
type: 'POST',
url: url1,
dataType: 'json',
success: function (data) {
$.ajax({
cache: false,
type: 'POST',
url:url2,
data: { para: list},
dataType: 'json',
success: function(result) {
......
}
})
}
})
複製程式碼
如上,魔鬼巢狀;
很快,隨著ES6的釋出,Promise橫空出世,之前多個AJAX多層巢狀的處理方式,看上去顯得那麼的low,如此的惡劣不堪,反觀Promise,高階大氣上檔次-------哈哈,是不是有點喜新厭舊的嫌疑啊------瞬間,讓我喜歡上了,有點一見鍾情的趕腳?
整個就是一大方優雅的典範啊:
readFile(filename).then(function (data) {
return data;
}).then(function (data) {
return readFile(data);
}).then(function (data) {
console.log(data);
}).catch(function(err){
......
});
複製程式碼
二、原理淺析
-
Promise 名如其實,Promise本意是承諾,在程式中的意思就是承諾我過一段時間後會給你一個結果。 什麼時候會用到過一段時間?答案是非同步操作,非同步是指可能比較長時間才有結果的才做,例如網路請求、讀取本地檔案等;
在這個過程中,Promise會經歷三個狀態:
- Pending Promise物件例項建立時候的初始狀態
- Fulfilled 可以理解為成功的狀態
- Rejected 可以理解為失敗的狀態
then 方法就是用來指定Promise 物件的狀態改變時確定執行的操作,resolve 時執行第一個函式(onFulfilled),reject 時執行第二個函式(onRejected)
- 示例分析:
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
if(Math.random()>0.5)
resolve('This is resolve!');
else
reject('This is reject!');
}, 1000);
});
promise.then(Fulfilled,Rejected)
複製程式碼
- 構造一個Promise例項需要給Promise建構函式傳入一個函式。
- 傳入的函式需要有兩個形參,兩個形參都是function型別的引數。
- 第一個形參執行後會讓Promise例項處於resolve狀態,所以我們一般給第一個形參命名為resolve,使 Promise 物件的狀態改變成成功,同時傳遞一個引數用於後續成功後的操作
- 第一個形參執行後會讓Promise例項處於reject狀態,所以我們一般給第一個形參命名為reject,將 Promise 物件的狀態改變為失敗,同時將錯誤的資訊傳遞到後續錯誤處理的操作
三、小試牛刀
經過一些時間的學習和摸索,筆者在ES6自帶的Promise的基礎上,實現了對其all、race、resolve、reject的功能模擬;
- Promise.all
- 引數:接受一個陣列,陣列內都是Promise例項。
- 返回值:返回一個Promise例項,這個Promise例項的狀態轉移取決於引數的Promise例項的狀態變化。當引數中所有的例項都處於resolve狀態時,返回的Promise例項會變為resolve狀態。如果引數中任意一個例項處於reject狀態,返回的Promise例項變為reject狀態。
- 程式碼如下
Promise.all = function(promises){
return new Promise(function(resolve,reject){
let done = gen(promises.length,resolve);
for(let i=0;i<promises.length;i++){
promises[i].then(function(data){
done(i,data);
},reject);
}
});
}
複製程式碼
- Promise.race
- 引數:接受一個陣列,陣列內都是Promise例項
- 返回值:返回一個Promise例項,這個Promise例項的狀態轉移取決於引數的Promise例項的狀態變化。當引數中任何一個例項處於resolve狀態時,返回的Promise例項會變為resolve狀態。如果引數中任意一個例項處於reject狀態,返回的Promise例項變為reject狀態。
- 程式碼如下:
Promise.race = function(promises){
return new Promise(function(resolve,reject){
for(let i=0;i<promises.length;i++){
promises[i].then(resolve,reject);
}
});
}
複製程式碼
- Promise.resolve
- 該方法返回一個Promise例項,這個例項處於resolve狀態。 會根據傳遞的引數不同而有不同的功能:
- 當引數是值(物件、陣列、字串等)型別的:作為resolve傳遞出去的值;
- 當引數是Promise例項:則原封不動返回;
- 程式碼如下:
//返回一個立刻成功的promise
//但該方法,需要傳入一個promise,但你只有一個普通的值,你就可以通過這個方法
//把這個普通的值(string number object)轉成一個promise物件
Promise.resolve = function(value){
return new Promise(function(resolve){
resolve(value);
});
}
複製程式碼
- Promise.reject
- 該方法返回一個Promise例項,這個例項處於reject狀態。
- 引數一般就是丟擲的錯誤資訊。
- 程式碼如下:
//返回一個立刻失敗的promise
Promise.reject = function(reason){
return new Promise(function(resolve,reject){
reject(reason);
});
}
複製程式碼
四、小結
以上就是在下對前端經常遇到的非同步處理方式的前認與後知;本人自知才疏學淺,如果有一些理解的有失偏頗之處,歡迎各位隨時拍磚與指正~!
當然,如果對您還有點作用的話,還望您評論鼓勵,以資我繼續前行,小可不勝感激~!