這里給大家分享我在網(wǎng)上總結(jié)出來的一些知識,希望對大家有所幫助
太長不看
- 不要嵌套使用函數(shù)。給每個函數(shù)命名并把他們放在你代碼的頂層
- 利用函數(shù)提升。先使用后聲明。
- 處理每一個異常
- 編寫可以復(fù)用的函數(shù),并把他們封裝成一個模塊
什么是“回調(diào)地獄”?
異步Javascript代碼,或者說使用callback的Javascript代碼,很難符合我們的直觀理解。很多代碼最終會寫成這樣:
fs.readdir(source, function (err, files) { if (err) { console.log('Error finding files: ' + err) } else { files.forEach(function (filename, fileIndex) { console.log(filename) gm(source + filename).size(function (err, values) { if (err) { console.log('Error identifying file size: ' + err) } else { console.log(filename + ' : ' + values) aspect = (values.width / values.height) widths.forEach(function (width, widthIndex) { height = Math.round(width / aspect) console.log('resizing ' + filename + 'to ' + height + 'x' + height) this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) { if (err) console.log('Error writing file: ' + err) }) }.bind(this)) } }) }) } })
看到上面金字塔形狀的代碼和那些末尾參差不齊的 }) 了嗎?這就是廣為人知的回調(diào)地獄了。
人們在編寫JavaScript代碼時,誤認為代碼是按照我們看到的代碼順序從上到下執(zhí)行的,這就是造成回調(diào)地獄的原因。在其他語言中,例如C,Ruby或者Python,第一行代碼執(zhí)行結(jié)束后,才會開始執(zhí)行第二行代碼,按照這種模式一直到執(zhí)行到當(dāng)前文件中最后一行代碼。隨著你學(xué)習(xí)深入,你會發(fā)現(xiàn)JavaScript跟他們是不一樣的。
什么是回調(diào)(callback)?
某種使用JavaScript函數(shù)的慣例用法的名字叫做回調(diào)。JavaScript語言中沒有一個叫“回調(diào)”的東西,它僅僅是一個慣例用法的名字。大多數(shù)函數(shù)會立刻返回執(zhí)行結(jié)果,使用回調(diào)的函數(shù)通常會經(jīng)過一段時間后才輸出結(jié)果。名詞“異步”,簡稱“async”,只是意味著“這將花費一點時間”或者說“在將來某個時間發(fā)生而不是現(xiàn)在”。通常回調(diào)只使用在I/O操作中,例如下載文件,讀取文件,連接數(shù)據(jù)庫等等。
當(dāng)你調(diào)用一個正常的函數(shù)時,你可以向下面的代碼那樣使用它的返回值:
var result = multiplyTwoNumbers(5, 10) console.log(result) // 50 gets printed out
然而使用回調(diào)的異步函數(shù)不會立刻返回任何結(jié)果。
var photo = downloadPhoto('http://coolcats.com/cat.gif') // photo is 'undefined'!
在這種情況下,上面那張gif圖片可能需要很長的時間才能下載完成,但你不想你的程序在等待下載完成的過程中中止(也叫阻塞)。
于是你把需要下載完成后運行的代碼存放到一個函數(shù)中(等待下載完成后再運行它)。這就是回調(diào)!你把回調(diào)傳遞給downloadPhoto
函數(shù),當(dāng)下載結(jié)束,回調(diào)會被調(diào)用。如果下載成功,傳入photo
給回調(diào);下載失敗,傳入error
給回調(diào)。
downloadPhoto('http://coolcats.com/cat.gif', handlePhoto) function handlePhoto (error, photo) { if (error) console.error('Download error!', error) else console.log('Download finished', photo) } console.log('Download started')
人們理解回調(diào)的最大障礙在于理解一個程序的執(zhí)行順序。在上面的例子中,發(fā)生了三件事情。
- 聲明
handlePhoto
函數(shù) -
downloadPhoto
函數(shù)被調(diào)用并且傳入了handlePhoto
最為它的回調(diào) - 打印出Download started。
請大家注意,起初handlePhoto
函數(shù)僅僅是被創(chuàng)建并被作為回調(diào)傳遞給了downloadPhoto
,它還沒有被調(diào)用。它會等待downloadPhoto
函數(shù)完成了它的任務(wù)才會執(zhí)行。這可能需要很長一段時間(取決于網(wǎng)速的快慢)。
這個例子意在闡明兩個重要的概念:
-
handlePhoto
回調(diào)只是一個存放將來進行的操作的方式 - 事情發(fā)生的順序并不是直觀上看到的從上到下,它會當(dāng)某些事情完成后再跳回來執(zhí)行。
怎樣解決“回調(diào)地獄”問題?
糟糕的編碼習(xí)慣造成了回調(diào)地獄。幸運的是,編寫優(yōu)雅的代碼不是那么難!
你只需要遵循三大原則:
1. 減少嵌套層數(shù)(Keep your code shallow)
下面是一堆亂糟糟的代碼,使用browser-request做AJAX請求。
var form = document.querySelector('form') form.onsubmit = function (submitEvent) { var name = document.querySelector('input').value request({ uri: "http://example.com/upload", body: name, method: "POST" }, function (err, response, body) { var statusMessage = document.querySelector('.status') if (err) return statusMessage.value = err statusMessage.value = body }) }
var form = document.querySelector('form') form.onsubmit = function formSubmit (submitEvent) { var name = document.querySelector('input').value request({ uri: "http://example.com/upload", body: name, method: "POST" }, function postResponse (err, response, body) { var statusMessage = document.querySelector('.status') if (err) return statusMessage.value = err statusMessage.value = body }) }
如你所見,給匿名函數(shù)一個名字是多么簡單,而且好處立竿見影:
- 起一個一望便知其函數(shù)功能的名字讓代碼更易讀
- 當(dāng)拋出異常時,你可以在stacktrace里看到實際出異常的函數(shù)名字,而不是"anonymous"
- 允許你合理安排函數(shù)的位置,并通過函數(shù)名字調(diào)用它
現(xiàn)在我們可以把這些函數(shù)放在我們程序的頂層。
document.querySelector('form').onsubmit = formSubmit function formSubmit (submitEvent) { var name = document.querySelector('input').value request({ uri: "http://example.com/upload", body: name, method: "POST" }, postResponse) } function postResponse (err, response, body) { var statusMessage = document.querySelector('.status') if (err) return statusMessage.value = err statusMessage.value = body }
請大家注意,函數(shù)聲明在程序的底部,但是我們在函數(shù)聲明之前就可以調(diào)用它。這是函數(shù)提升的作用。
2.模塊化(Modularize)
任何人都有有能力創(chuàng)建模塊,這點非常重要。寫出一些小模塊,每個模塊只做一件事情,然后把他們組合起來放入其他的模塊做一個復(fù)雜的事情。只要你不想陷入回調(diào)地獄,你就不會。讓我們把上面的例子修改一下,改為一個模塊。
下面是一個名為formuploader.js
的新文件,包含了我們之前使用過的兩個函數(shù)。
module.exports.submit = formSubmit function formSubmit (submitEvent) { var name = document.querySelector('input').value request({ uri: "http://example.com/upload", body: name, method: "POST" }, postResponse) } function postResponse (err, response, body) { var statusMessage = document.querySelector('.status') if (err) return statusMessage.value = err statusMessage.value = body }
module.exports
是node.js模塊化的用法。現(xiàn)在已經(jīng)有了?formuploader.js
?文件,我們只需要引入它并使用它。請看下面的代碼:
var formUploader = require('formuploader') document.querySelector('form').onsubmit = formUploader.submit
我們的應(yīng)用只有兩行代碼并且還有以下好處:
- 方便新開發(fā)人員理解你的代碼 -- 他們不需要費盡力氣讀完
formuploader
函數(shù)的全部代碼 -
formuploader
可以在其他地方復(fù)用
3.處理每一個異常(Handle every single error)
有三種不同類型的異常:語法異常,運行時異常和平臺異常。語法異常通常由開發(fā)人員在第一次解釋代碼時捕獲,運行時異常通常在代碼運行過程中因為bug觸發(fā),平臺異常通常由于沒有文件的權(quán)限,硬盤錯誤,無網(wǎng)絡(luò)鏈接等問題造成。這一部分主要來處理最后一種異常:平臺異常。
前兩個大原則意在提高代碼可讀性,但是第三個原則意在提高代碼的穩(wěn)定性。在你與回調(diào)打交道的時候,你通常要處理發(fā)送請求,等待返回或者放棄請求等任務(wù)。任何有經(jīng)驗的開發(fā)人員都會告訴你,你從來不知道哪里回出現(xiàn)問題。所以你有必要提前準(zhǔn)備好,異??偸菚l(fā)生。
把回調(diào)函數(shù)的第一個參數(shù)設(shè)置為error對象,是Node.js中處理異常最流行的方式。文章來源:http://www.zghlxwxcb.cn/news/detail-760445.html
var fs = require('fs') fs.readFile('/Does/not/exist', handleFile) function handleFile (error, file) { if (error) return console.error('Uhoh, there was an error', error) // otherwise, continue on and use `file` in your code }
error
對象是一個約定俗成的慣例,提醒你記得去處理異常。如果它是第二個參數(shù),你更容易把它忽略掉。本文轉(zhuǎn)載于:
https://juejin.cn/post/7294166986195533843
如果對您有所幫助,歡迎您點個關(guān)注,我會定時更新技術(shù)文檔,大家一起討論學(xué)習(xí),一起進步。
?文章來源地址http://www.zghlxwxcb.cn/news/detail-760445.html
到了這里,關(guān)于記錄--沒有await,如何處理“回調(diào)地獄”的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!