異步與同步相比,最難以掌控的就是異步的任務會何時完成和完成以後的回調問題,javascript
難以掌控的觸發狀態,讓你本身寫的代碼當時還能夠讀懂,可是過幾天、半個月以後若是不從新盤一邊邏輯,你哪知道哪一個內容會先執行,借用這麼一個例子java
listen( "click", function handler(evt){
setTimeout( function request(){
ajax( "http://some.url.1", function response(text){
if (text == "hello") {
handler();
}
else if (text == "world") {
request();
}
} );
}, 500) ;
} );
doSomething();
複製代碼
很難以理解這種地獄式的回調(回調地獄)會對可讀性有多麼大的摧毀。面試
首先 執行listern()ajax
其次 doSomething()數組
500ms(或者更遠)後執行ajax()promise
ajax完成後dom
若是text === hello 執行handler()異步
若是text === world 執行request()async
難受嗎???函數
在你不知道的javascript一書中,對於回調的信任問題作了闡述 當你使用第三方的庫的方法處理回調時頗有可能遇到如下信任內容:
怎麼解決???? 這種信任問題該怎麼辦?
當你把一件事情交給別人去作(可能立刻就能完成的也多是須要一段時間的)這我的在任務完成或者失敗後都會給你一個迴應,這樣的人你是否是特別放心的把事情交給他,他沒回應你那麼他是正在辦事、迴應你了就是成功了或者失敗了。
Promise的實例有三個狀態,Pending(進行中)、Resolved(已完成)、Rejected(已拒絕)。當你把一件事情交給promise時,它的狀態就是Pending,任務完成了狀態就變成了Resolved、沒有完成失敗了就變成了Rejected。
言歸正傳:寫一個簡單的promise
let promise = new Promise((resolve,reject)=>{
// 接收一個callback。參數是成功函數與失敗函數
setTimeout(()=>{
let num = parseInt(Math.random()*100);
// 若是數字大於50就調用成功的函數,而且將狀態變成Resolved
if(num > 50){
resolve(num);
}else{
// 不然就調用失敗的函數,將狀態變成Rejected
reject(num)
}
},10000)
})
複製代碼
當Promise執行的內容符合你預期的成功條件的話,就調用resolve函數,失敗就調用reject函數,這兩個函數的參數會被promise捕捉到。能夠在以後的回調中使用。
建立一個承諾咱們已經作完了,那麼如何使用承諾後的結果呢?
promise.then(res=>{
console.log(res);
//在構造函數中若是你執行力resolve函數就會到這一步
},err=>{
// 執行了reject函數會到這一步
console.log(err);
})
複製代碼
then方法接收兩個函數,第一個是承諾成功(狀態爲resolved)的回調函數,一個承諾失敗(狀態爲rejected)的回調函數。
then方法的返回值不是一個promise對象就會被包裝成一個promise對象,因此then方法支持鏈式調用。
promise.then(res=>{ return 42}).then(res=>{console.log(res)})
// 打印出42
複製代碼
then方法的鏈式調用能夠幫咱們串行的解決一些邏輯,當咱們平時書寫有順序的異步時間,好比
ajax('first');
ajax('second');
ajax('third');
須要按順序來執行怎麼辦?
ajax('first').success(function(res){
ajax('second').success(function(res){
ajax('third').success(function(res){
//串行完畢能夠執行你想要的內容了
});
})
})
多麼美麗而又讓人望而卻步的三角形啊!!
複製代碼
若是使用then的鏈式調用呢?
let promise = new Promise((resolve,reject)=>{
ajax('first').success(function(res){
resolve(res);
})
})
promise.then(res=>{
return new Promise((resovle,reject)=>{
ajax('second').success(function(res){
resolve(res)
})
})
}).then(res=>{
return new Promise((resovle,reject)=>{
ajax('second').success(function(res){
resolve(res)
})
})
}).then(res=>{
// 串行完畢你要作的xxx能夠開始了
})
複製代碼
並且每次執行resolve的時候,均可以把每次ajax的回調數據進行傳遞到最後。清晰簡單明瞭。
說完串行了,那麼並行怎麼辦??? 當有多個異步事件,之間並沒有聯繫並且沒有前後順序,只須要所有完成就能夠開始工做了。
串行會把每個異步事件的等待時間進行一個相加,明顯會對完成進行一個阻塞。那麼並行的話該怎麼肯定所有完成呢?
Promise.all 接收一個數組,數組的每一項都是一個promise對象。當數組中全部的promise的狀態都達到resolved的時候,Promise.all的狀態就會變成resolved,若是有一個狀態變成了rejected,那麼Promise.all的狀態就會變成rejected(任意一個失敗就算是失敗),這就能夠解決咱們並行的問題。調用then方法時的結果成功的時候是回調函數的參數也是一個數組,按順序保存着每個promise對象resolve執行時的值。
let promise1 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(1);
},10000)
});
let promise2 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(2);
},9000)
});
let promise3 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(3);
},11000)
});
Promise.all([promise1,promise2,promise3]).then(res=>{
console.log(res);
//[1,2,3] 證實與哪一個promise的狀態先變成resolved無關
})
let promise1 = new Promise((resolve,reject)=>{
setTimeout(()=>{
reject(1);
},10000)
});
let promise2 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(2);
},9000)
});
let promise3 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(3);
},11000)
});
let promiseAll =Promise.all([promise1,promise2,promise3]);
promiseAll.then(res=>{
console.log(res);
},err=>{
console.log(err)
})
複製代碼
看結果不難看出來符合以前所說的
Promise.race 競速模式 也是接受一個每一項都是promise的數組。可是與all不一樣的是,第一個promise對象狀態變成resolved時自身的狀態變成了resolved,第一個promise變成rejected自身狀態就會變成rejected。第一個變成resolved的promsie的值就會被使用。
let promise1 = new Promise((resolve,reject)=>{
setTimeout(()=>{
reject(1);
},10000)
});
let promise2 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(2);
},9000)
});
let promise3 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(3);
},11000)
});
Promise.race([promise1,promise2,promise3]).then(res=>{
console.log(res);
//打印出2 爲何不打印出1呢?由於promise2先完成了其他的就忽略來
},rej=>{
console.log('rejected');
console.log(rej)};
)
// 你們能夠嘗試本身改變時間進行測試
複製代碼
Promsie.race還有一個很重要的實際用處就是,有時候咱們要去作一件事,可是超過三秒鐘左右咱們就不作了那怎麼辦? 這個時候可使用Promise.race方法
Promise.race([promise1,timeOutPromise(3000)]).then(res=>{})
// timeOutPromise延時3s左右 因爲是用setTimeout來實現的並不必定準確3s(通常主線程在開發中不會阻塞3s以上的因此不會有太大問題)
複製代碼
這就是我對於Promise的一些基本理解。
很難受的一件事 白天辛苦寫的1736個字的內容莫名其妙的被我刪掉了。。。。。內容都去哪了??? 很藍瘦。。。 因此晚上又從新梳理了一遍。
下一期的內容是針對於網上常見的Promise的自我實現進行一個分析,
總之一句話抓住Promise的承諾思想,就能夠很好的去編寫promise的代碼。
async 與await將會在下期或者下下期進行講解。(很抱歉,想一口氣講完的可是內容太多,我也須要慢慢梳理爭取給你們一個高質量的文章,)