在了解 Callback Functions Hell ,必須先知道甚麼是 Callback Functions ,而 Callback Functions 怎麼造成 Callback Functions Hell。
Callback Functions
其實有寫過 JS 的 都應該有用過 Callback Functions(以下簡稱 Callback ),像是常用的 forEach() 、 map()、filter()、setTimeout() 等等。
什麼是 Callback ?
範例一
let arr = [1, 2, 3]
arr.forEach(a => a % 2 != 0)
又或者是
範例二
function getMsg(){
console.log('Hello Ajax')
}
function getResponse(cb){
let xhr = new XMLHttpRequest()
xhr.open('GET', 'https://jsonplaceholder.typicode.com/todos/1')
xhr.send()
xhr.addEventListener('readystatechange', (e)=>{
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr < 300){
cb()
}
}
})
}
getResponse(getMsg)
在 freeCodeCamp 中 What is a Callback Function in JavaScript? 寫到:
A callback function is a function that is passed as an argument to another function, to be “called back” at a later time. A function that accepts other functions as arguments is called a higher-order function.
簡單來說 Callback Function 指的就是做為另一個函數(以下稱函數 A )的引數,並且這個引數在函數 A 中會被調用,而這個接收其他函數作為引數的函數 A 又可以稱做 Higher-Order Function(高階函數)。
所以上面那 2 個 JS 範例, 範例一中 forEach() 帶入的 a => a % 2 != 0 及範例二中 getResponse() 帶入的 getMsg 都是 Callback Function 。
Callback Functions 怎麼變成 Callback Functions Hell 的?
假使透過異步函數得到資料後,要在執行另一個異步函數去取得另一個資料的話,以 Callback Functions 來寫的話會是怎樣?
function getResponse(url, cb){
let xhr = new XMLHttpRequest()
xhr.open('GET', url)
xhr.send()
xhr.addEventListener('readystatechange', (e)=>{
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
cb(undefined, JSON.parse(xhr.responseText))
}
else{
cb('cann\'t fetch!', undefined)
}
}
})
}
getResponse('https://jsonplaceholder.typicode.com/todos/1', (err, data) => {
console.log(err, data)
// 取得 todos/1 資料後,再去調用 getResponse() 取得另一筆 todos/3 的資料
getResponse('https://jsonplaceholder.typicode.com/todos/3', (err, data) => {
console.log(err, data)
})
})
而 Callback Functions Hell 的形成就是因為太多的 Callback Functions 被一層一層執行下去,導致代碼難以維護。
getResponse('https://jsonplaceholder.typicode.com/todos/1', (err, data) => {
console.log(err, data)
getResponse('https://jsonplaceholder.typicode.com/todos/3', (err, data) => {
console.log(err, data)
getResponse('https://jsonplaceholder.typicode.com/todos/5', (err, data) => {
console.log(err, data)
getResponse('https://jsonplaceholder.typicode.com/todos/5', (err, data) => {
console.log(err, data)
getResponse('https://jsonplaceholder.typicode.com/todos/5', (err, data) => {
console.log(err, data)
})
})
})
})
})
上面這個範例看起來是不是會覺得很雜亂,想修改也無從下手的感覺,再想想看如果在繼續不斷的在上一層中調用 Callback Function 的話,是不是會覺得很恐怖,這也是為什麼會被稱作 Callback Functions Hell 。



















