【相關推薦:、】
錯誤是程式設計過程的一部分。編寫程式的過程難免會出現一些錯誤,通過這些產生的錯誤,我們可以學會如何避免遇到這樣的情況,以及如何在下次做的更好。
在 JavaScript 中,當程式碼語句緊密耦合併產生錯誤時,繼續使用剩餘的程式碼語句是沒有意義的。相反,我們試圖儘可能優雅地從錯誤中恢復過來。JavaScript 直譯器在出現此類錯誤時檢查例外處理程式碼,如果沒有例外處理程式,程式將返回導致錯誤的任何函數。
對呼叫堆疊上的每個函數重複此操作,直到找到例外處理程式或到達頂層函數,從而導致程式以錯誤終止,導致程式的崩潰。
一般來說,有兩種處理方式:
丟擲異常 — 如果在執行時發生的問題無法得到有意義的處理,最好丟擲它
function openFile(fileName) { if (!exists(fileName)) { throw new Error('找不到檔案 ' + fileName) } // ... }
捕獲異常 — 丟擲的異常在執行時更有意義的地方被捕獲和處理
try { openFile('../test.js') } catch(e) { // 優雅地處理丟擲的期望 }
讓我們更詳細地瞭解這些操作。
您可能會看到類似 ReferenceError: specs is not defined 這樣的情況。這表示通過 throw 語句引發的異常。
語法
throw «value» // 不要這樣做 if (somethingBadHappened) { throw 'Something bad happened' }
對可以作為異常丟擲的資料型別沒有限制,但 JavaScript 具有特殊的內建異常型別。其中之一是 Error,正如您在前面的範例中所看到的。這些內建的異常型別為我們提供了比異常訊息更多的細節。
Error
Error 型別用於表示一般異常。這種型別的異常最常用於實現使用者定義的異常。它有兩個內建屬性可供使用。
message — 作為引數傳遞給 Error 建構函式的內容。例如,new Error('This is an error message')。您可以通過 message 屬性存取訊息。
const myError = new Error('Error!!!') console.log(myError.message) // Error!!!
stack — 該屬性返回導致錯誤的檔案的歷史記錄(呼叫堆疊)。堆疊頂部還包括 message,後面是實際堆疊,從最新/隔離的錯誤點開始,到最外部負責的檔案。
Error: Error!!! at <anonymous>:1:1
注意:new Error('...') 在丟擲之前不會執行任何操作,即 throw new Error('error msg') 將在 JavaScript 中建立一個 Error 範例,並停止指令碼的執行,除非您對 Error 錯誤執行某些操作,例如捕獲它。
現在我們知道了什麼是異常以及如何丟擲它們,讓我們討論一下如何通過捕獲它們來阻止它們破壞我們的程式。
try-catch-finally 是處理異常的最簡單方法。
try { // 要執行的程式碼 } catch (e) { // 發生異常時要執行的程式碼 } [ // 可選 finally { // 無論發生異常都始終執行的程式碼 } ]
在 try 子句中,我們新增了可能產生異常的程式碼。如果發生異常,則執行 catch 子句。
有時,無論程式碼是否產生異常,都需要執行程式碼,這時我們可以使用可選塊 finally。
即使 try 或 catch 子句執行 return 語句,finally 塊也將執行。例如,以下函數返回 'Execute finally',因為 finally 子句是最後執行的內容。
function foo() { try { return true } finally { console.log('Execute finally') } }
我們在無法事先檢查程式碼正確性的地方使用 try-catch。
const user = '{"name": "D.O", "age": 18}' try { // 程式碼執行 JSON.parse(params) // 在出現錯誤的情況下,其餘的程式碼將永遠無法執行 console.log(params) } catch (err) { // 在異常情況下執行的程式碼 console.log(err.message) // params is not defined }
如上所示,在執行程式碼之前,不可能檢查 JSON.parse 以獲得 stringify 物件或字串。
注意:您可以捕獲程式產生的異常和執行時異常,但無法捕獲 JavaScript 語法錯誤。
try-catch-finally 只能捕獲同步錯誤。如果我們嘗試將其用於非同步程式碼,那麼在非同步程式碼完成其執行之前,try-catch-finally 可能已經執行了。
回撥函數
使用回撥函數(不推薦),我們通常會收到兩個如下所示的引數:
async function(code, (err, result) => { if (err) return console.error(err) console.log(result) })
我們可以看到有兩個引數:err 和 result。如果有錯誤,err 引數將等於該錯誤,我們可以丟擲該錯誤來進行例外處理。
在 if (err) 塊中返回某些內容或將其他指令包裝在 else 塊中都很重要。否則,您可能會遇到另一個錯誤。例如,當您嘗試存取 result.data 時,result 可能未定義。
Promises
使用 promises 的 then 或者 catch,我們可以通過將錯誤處理程式傳遞給 then 方法或使用 catch 子句來處理錯誤。
promise.then(onFulfilled, onRejected)
也可以使用 .catch(onRejected) 而不是 .then(null, onRejected) 新增錯誤處理程式,其工作方式相同。
讓我們看一個 .catch 拒絕 Promise 的例子。
Promise.resolve('1') .then(res => { console.log(res) // 1 throw new Error('go wrong') // 丟擲異常 }) .then(res => { console.log(res) // 不會被執行 }) .catch(err => { console.error(err) // 捕獲並處理異常 ——> Error: go wrong })
使用 async/await 和 try-catch
使用 async/await 和 try-catch-finally,處理異常是輕而易舉的事。
async function func() { try { await nonExistentFunction() } catch (err) { console.error(err) // ReferenceError: nonExistentFunction is not defined } }
現在我們已經很好地理解了如何在同步和非同步程式碼塊中執行例外處理,讓我們回答本文最後一個待解決的問題 :我們如何處理未捕獲的異常?
在瀏覽器中
我們可以使用 window.onerror() 方法來處理未捕獲的異常。每當執行時發生錯誤時,該方法會在 window 物件上觸發 error 事件。
onerror() 的另一個實用做法是:當站點中的圖片或視訊等資料載入出錯時,可以用該方法觸發某些操作。例如,提供一張載入出錯時的圖片,或顯示一條訊息。
<img src="logo.png" onerror="alert('Error loading picture.')" />
在 Node.js 中
EventEmitter 模組派生的 process 物件可以訂閱事件 uncaughtException。
process.on('uncaughtException', () => {})`
我們可以傳遞一個回撥來處理異常。如果我們嘗試捕獲這個未捕獲的異常,程序將不會終止,因此我們必須手動完成。
uncaughtException 僅適用於同步程式碼。對於非同步程式碼,還有另一個稱為 unhandledRejection 的事件。
process.on('unhandledRejection', () => {})
決不要嘗試為基本 Error 型別實現 「捕獲所有」 處理程式。這將混淆所發生的一切,並損害程式碼的可維護性和可延伸性。
關鍵要點
throw 語句用於生成使用者定義的異常。在執行時,當 throw 遇到語句時,當前函數的執行將停止,控制權將傳遞給 catch 呼叫堆疊中的第一個子句。如果沒有 catch 子句,程式將終止
JavaScript 有一些內建的異常型別,最值得注意的是 Error,它返回 Error 中的兩個重要屬性:stack 和 message。
try 子句將包含可能產生異常的程式碼,catch 子句會在發生異常時執行。
對於非同步程式碼,最好使用 async/await 配合 try-catch 語句。
可以捕獲未處理的異常,這可以防止應用程式崩潰。
不要覺得麻煩,例外處理可以幫助您提高程式碼的可維護性、可延伸性和可讀性。
【相關推薦:、】
以上就是一起分析JavaScript例外處理方式的詳細內容,更多請關注TW511.COM其它相關文章!