同期非同步系列文章推薦
談一談javascript非同步
javascript非同步中的回撥
javascript非同步之Promise.all()、Promise.race()、Promise.finally()
javascript非同步之Promise.resolve()、Promise.reject()
javascript非同步之Promise then和catch
javascript非同步之async(一)
javascript非同步之async(二)
javascript非同步實戰
javascript非同步總結歸檔
我們說處理javascript非同步最常用的方式就是通過回撥函式,對於回撥函式我們昨天對此做了介紹
簡單快速,
我們一般使用巢狀回撥或者鏈式回撥,會產生以下問題
- 當採用巢狀回撥時,會導致層級太多,不利於維護
- 所以我們又採用了鏈式回撥,對巢狀回撥進行拆分,拆分後的函式間耦合度很高,
- 如果需要傳遞引數,函式之間的關聯性會更高,而且要對引數進行校驗以提高程式碼的健壯性
-
如果將我們自己的回撥函式傳遞給第三方外掛或者庫,就要考慮一些不可控因素
- 呼叫回撥過早
- 呼叫回撥過晚(或不被呼叫)
- 呼叫回撥次數過多或者過少
promise的存在就是為了解決以上問題
雖然我們日常寫回撥函式不會有這麼嚴格的要求,但是如果不這樣去寫回撥函式,就會存在隱患,當在團隊協作的時候,顯得編碼規範顯得尤為重要
本文不重點介紹如何使用promise,重點介紹的是promise解決了哪些非同步回撥出現的問題。
什麼是promise
我們來看一個場景,有助於我們瞭解promise
設想一下這個場景,我去KFC,交給收銀員10元,下單買一個漢堡,下單付款。到這裡,我已經發出了一個請求(買漢堡),啟動了一次交易。
但是做漢堡需要時間,我不能馬上得到這個漢堡,收銀員給我一個收據來代替漢堡。到這裡,收據就是一個承諾(promise),保證我最後能得到漢堡。
所以我需要好好的保留的這個收據,對我來說,收據就是漢堡,雖然這張收據不能吃,我需要等待漢堡做好,等待收銀員叫號通知我
等待的過程中,我可以做些別的事情
收銀員終於叫到了我的號,我用收據換來了漢堡
當然還有一種情況,當我去櫃檯取漢堡的時候,收銀員告訴我漢堡賣光了,做漢堡的師傅受傷了等等原因,導致了我無法得到這個漢堡
雖然我有收據(承諾),但是可能得到漢堡(成功),可能得不到漢堡(失敗)
我由等待漢堡變成了等到或者等不到,這個過程不可逆,
上面很形象的介紹了promise,上面的等待漢堡和得到漢堡,漢堡賣光了,得不到漢堡,分別對應promise的三種狀態
三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)(一旦狀態改變,就不會再變)
回撥函式呼叫過早
呼叫過早就是將非同步函式作為同步處理了,
我們之前說過,javascript以單執行緒同步的方式執行主執行緒,遇到非同步會將非同步函式放入到任務佇列中,
當主執行緒執行完畢,會迴圈執行任務佇列中的函式,也就是事件迴圈,直到任務佇列為空。
事件迴圈和任務佇列
事件迴圈就像是一個遊樂場,玩過一個遊戲後,你需要重新排到隊尾才能再玩一次
任務佇列就是,在你玩過一個遊戲後,可以插隊接著玩
我們看一個栗子
const promise = new Promise((resolve, reject) => {
resolve("成功啦")
});
promise.then(res => {
console.log(res);
console.log("我是非同步執行的");
})
console.log(`我在主執行緒`);
看下輸出,重點看輸出順序
//我在主執行緒
//成功啦
//我是非同步執行的
直接手動是promise的狀態切為成功狀態,console.log(“我是非同步執行的”);這段程式碼也是非同步執行的
提供給then()的回撥永遠都是非同步執行的,所以promise中不會出現回撥函式過早執行的情況
回撥函式呼叫過晚或不被呼叫
回撥函式呼叫過晚
回撥函式呼叫過晚的處理原理和呼叫過早很類似,
在promise的then()中存放著非同步函式,所有的非同步都存在於js的任務佇列中,當js的主執行緒執行完畢後,會依次執行任務佇列中的內容,不會出現執行過晚的情況
回撥函式不被呼叫
我們用栗子說話
const promise = new Promise((resolve, reject) => resolve(`成功啦`))
promise.then(s => console.log(s));
console.log(`我在主執行緒`);
成功狀態的輸出
//我在主執行緒
//成功啦
成功狀態下回撥被呼叫
繼續看一下失敗的回撥
const promise = new Promise((resolve, reject) => reject(`失敗啦`))
promise.then(null, s => console.log(s));
console.log(`我在主執行緒`);
失敗狀態的輸出
//我在主執行緒
//失敗啦
失敗狀態下回撥被呼叫
所以說,不管是失敗還是成功,回撥函式都會被呼叫
回撥函式呼叫次數過多或者過少
呼叫次數過多
我們之前說了promise有三種狀態
pending(進行中)、fulfilled(已成功)和rejected(已失敗)狀態一旦狀態改變,就不會再變
一個栗子
const promise = new Promise((resolve, reject) => {
reject(`失敗啦`)
resolve(`成功啦`)
});
promise.then(res => {
console.log(`我是非同步執行的成功:${res}`);
},err=>{
console.log(`我是非同步執行的失敗:${err}`);
}).catch(err => {
console.log(err);
})
console.log(`我在主執行緒`);
輸出
//我在主執行緒
//我是非同步執行的失敗:失敗啦
當狀態變為失敗時,就不會再變為成功,成功的函式也不會執行,反之亦然
呼叫次數過少
回撥函式正常是呼叫一次,過少=>0次=>回撥函式不被呼叫,上面剛剛討論過