前言
這個是作者寫的面試篇章系列第一章,基本源於作者之前一個月內的面試總結,謝謝觀看。
回撥是啥?為什麼叫回撥地獄?
do('eat', (dishes) => {
//吃完飯後再去洗盤子
washDishes(dishes)
})
複製程式碼
上面的程式碼,大家都常常看到,包括ajax、各種模組的方法等等,他們都是回撥函式。
其實就是在執行某些操作(吃飯)後,得到特定資料(盤子),再去呼叫的一個方法(洗盤子)。
我用著挺好的,為什麼會出現回撥地獄呢?
ajax1(url, () => {
ajax2(url, () => {
ajax3(url, () => {
doSomething()
})
})
})
複製程式碼
如果在寫業務程式碼的時候,有好幾個介面需要你使用,然鵝介面A需要介面B的回撥res引數去請求資料呢? 所以就會寫成三四個回撥函式巢狀。
這樣寫程式碼,雖然看著挺好的,但是少的還好,如果7、8個類似場景就爆炸了!
首先說下缺點
- 程式碼耦合,一旦修改,原地爆炸。
- 無法使用try catch,就無法排錯,也是原地爆炸。
大佬們大家一起想辦法,想著想著,就有以下幾種作者擅長的解決方案。
1. generator
const eat = function* () {
yield 1;
yield 2;
return 3;
}
let do = eat();
do.next(); // { value: 1, done: false }
do.next(); // { value: 2, done: false }
do.next(); // { value: 3, done: true }
do.next(); // { value: undefined, done: true }
複製程式碼
這是一種解決辦法,詳情可以看阮一峰老師的es6標準入門(作者不想展開)。
2. promise
let eat = () => {
return new Promise((resolve, reject) => {
resolve('俺吃好啦,給你盤子')
})
}
eat.then( res => {
//吃完後給你再洗盤子
let washResult = washDishes(res);
return washResult;
})
.then(res => {
//洗完盤子後,你媽媽甚至還獎勵你吃冰淇淋!
eatIceCream(res)
})
複製程式碼
這個可是好東西啊,promise就像是你在追求的女孩阿珍。
他有三種狀態:等待中(pending) 完成了 (resolved) 拒絕了(rejected)。
你給阿珍送了跟項鍊,阿珍在想,到底要不要接收阿強呢?這個就是pending 等待中。
阿珍覺得你挺不錯的,三圍都是180,嗯。接受你了!我們阿強時候親吻阿珍了。這個就是resovled 完成了。
阿珍覺得阿偉比你帥,不想接受你的求愛,拒絕你了,整個流程碰到錯誤了有問題了。這就是reject 拒絕了
這個就是簡單的promise了。
3. async/await
async function eat () {
let washResult = await washDishes();
let eatIceCream = await buyIceCream(washResult);
let eatCake = await buyCake(eatIceCream);
//你媽媽看你吃的多,再獎勵大胖兒子一個cake!
}
複製程式碼
這個東西呢,其實就是一層語法糖,加上async命令的函式,會return出一個promise。
意思和阿強愛上了阿珍一個道理,只是追求阿珍的路上方便了不少。
回到題目!你知道什麼是回撥地獄嗎?你可以這樣說。
- 回答回撥函式是啥?
- 為什麼會有回撥地獄?
- 我該如何解決?
- 擴充套件你的解決辦法。
- 擴充套件你的解決辦法。
- 擴充套件你的解決辦法。
例如作者自己對這個問題的解答如下:
1.因為javascript是單執行緒的,所以有些需要等待的地方,需要使用回撥函式。
2.由於某些業務的問題,在程式碼中會一次性寫會多層的回撥巢狀,回撥巢狀後的程式碼的維護難度,和無法排除bug。這個就被稱作回撥地獄。
3.我在工作中,一般處理的方式是使用promise或者async函式。
4.promise由於xxxx 對於開發這種多層巢狀的程式碼很方便,降低了程式碼的維護難度等等。
5.promise是XXX時新增的,擁有著xxxx的特性等等。
6.promise下面的all函式我也經常用到xxxxxxx
7.你甚至還可以手寫個promise!
複製程式碼