内容 | 網址 |
---|---|
JavaScript個人學習筆記總結 - 快速入門 | https://blog.csdn.net/weixin_50594210/article/details/115112096 |
JavaScript個人學習筆記總結 - 函數 | https://blog.csdn.net/weixin_50594210/article/details/115113081 |
JavaScript個人學習筆記總結 - 标準對象 | https://blog.csdn.net/weixin_50594210/article/details/115112683 |
JavaScript個人學習筆記總結 - 面向對象程式設計 | https://blog.csdn.net/weixin_50594210/article/details/115113024 |
JavaScript個人學習筆記總結 - 浏覽器 | https://blog.csdn.net/weixin_50594210/article/details/115113131 |
JavaScript個人學習筆記總結 - jQuery | https://blog.csdn.net/weixin_50594210/article/details/115113299 |
JavaScript個人學習筆記總結 - 錯誤處理 | https://blog.csdn.net/weixin_50594210/article/details/115113442 |
JavaScript個人學習筆記總結 - underscore | https://blog.csdn.net/weixin_50594210/article/details/115113498 |
文章目錄
- 錯誤處理
-
- 1、錯誤傳播
- 2、異步錯誤處理
錯誤處理
在執行JavaScript代碼的時候,有些情況下會發生錯誤。
錯誤分兩種,一種是程式寫的邏輯不對,導緻代碼執行異常。例如:
var s = null;
var len = s.length; // TypeError:null變量沒有length屬性
對于這種錯誤,要修複程式。
一種是執行過程中,程式可能遇到無法預測的異常情況而報錯,例如,網絡連接配接中斷,讀取不存在的檔案,沒有操作權限等。
對于這種錯誤,我們需要處理它,并可能需要給使用者回報。
錯誤處理是程式設計時必須要考慮的問題。對于C這樣貼近系統底層的語言,錯誤是通過錯誤碼傳回的:
int fd = open("/path/to/file", O_RDONLY);
if (fd == -1) {
printf("Error when open file!");
} else {
// TODO
}
通過錯誤碼傳回錯誤,就需要約定什麼是正确的傳回值,什麼是錯誤的傳回值。上面的open()函數約定傳回-1表示錯誤。
顯然,這種用錯誤碼表示錯誤在編寫程式時十分不便。
是以,進階語言通常都提供了更抽象的錯誤處理邏輯try … catch … finally,JavaScript也不例外。
分析一下使用try … catch … finally的執行流程。
<script>
var r1, r2, s = null;
try {
r1 = s.length; // 此處應産生錯誤
r2 = 100; // 該語句不會執行
} catch (e) {
console.log('出錯了:' + e);
} finally {
console.log('finally');
}
console.log('r1 = ' + r1); // r1應為undefined
console.log('r2 = ' + r2); // r2應為undefined
</script>
當代碼塊被
try { ... }
包裹的時候,就表示這部分代碼執行過程中可能會發生錯誤,一旦發生錯誤,就不再繼續執行後續代碼,轉而跳到
catch
塊。
catch (e) { ... }
包裹的代碼就是錯誤處理代碼,變量
e
表示捕獲到的錯誤。最後,無論有沒有錯誤,finally一定會被執行。
是以,有錯誤發生時,執行流程像這樣:
- 先執行
的代碼;try { ... }
- 執行到出錯的語句時,後續語句不再繼續執行,轉而執行
代碼;catch (e) { ... }
- 最後執行
代碼。finally { ... }
而沒有錯誤發生時,執行流程像這樣:
- 先執行
的代碼;try { ... }
- 因為沒有出錯,
代碼不會被執行;catch (e) { ... }
- 最後執行
代碼。finally { ... }
最後請注意,
catch
和
finally
可以不必都出現。也就是說,
try
語句一共有三種形式:
完整的try … catch … finally:
try {
...
} catch (e) {
...
} finally {
...
}
隻有try … catch,沒有finally:
try {
...
} catch (e) {
...
}
隻有try … finally,沒有catch:
try {
...
} finally {
...
}
- 錯誤類型
JavaScript有一個标準的
Error
對象表示錯誤,還有從
Error
派生的
TypeError
、
ReferenceError
等錯誤對象。我們在處理錯誤時,可以通過
catch(e)
捕獲的變量e通路錯誤對象:
<script>
try {
...
} catch (e) {
if (e instanceof TypeError) {
alert('Type error!');
} else if (e instanceof Error) {
alert(e.message);
} else {
alert('Error: ' + e);
}
}
</script>
使用變量
e
是一個習慣用法,也可以以其他變量名命名,如
catch(ex)
。
- 抛出錯誤
程式也可以主動抛出一個錯誤,讓執行流程直接跳轉到
catch
塊。抛出錯誤使用
throw
語句。
實際上,JavaScript允許抛出任意對象,包括數字、字元串。但是,最好還是抛出一個Error對象。
最後,當我們用catch捕獲錯誤時,一定要編寫錯誤處理語句:
<script>
var n = 0, s;
try {
n = s.length;
} catch (e) {
console.log(e);
}
console.log(n);
</script>
哪怕僅僅把錯誤列印出來,也不要什麼也不幹:
<script>
var n = 0, s;
try {
n = s.length;
} catch (e) {
}
console.log(n);
</script>
因為catch到錯誤卻什麼都不執行,就不知道程式執行過程中到底有沒有發生錯誤。
處理錯誤時,請不要簡單粗暴地用
alert()
把錯誤顯示給使用者。教程的代碼使用
alert()
是為了便于示範。
1、錯誤傳播
如果代碼發生了錯誤,又沒有被try … catch捕獲,那麼,程式執行流程會跳轉到哪呢?
<script>
function getLength(s) {
return s.length;
}
function printLength() {
console.log(getLength('abc')); // 3
console.log(getLength(null)); // Error!
}
printLength();
</script>
如果在一個函數内部發生了錯誤,它自身沒有捕獲,錯誤就會被抛到外層調用函數,如果外層函數也沒有捕獲,該錯誤會一直沿着函數調用鍊向上抛出,直到被JavaScript引擎捕獲,代碼終止執行。
是以,我們不必在每一個函數内部捕獲錯誤,隻需要在合适的地方來個統一捕獲,一網打盡:
<script>
function main(s) {
console.log('BEGIN main()');
try {
foo(s);
} catch (e) {
console.log('出錯了:' + e);
}
console.log('END main()');
}
function foo(s) {
console.log('BEGIN foo()');
bar(s);
console.log('END foo()');
}
function bar(s) {
console.log('BEGIN bar()');
console.log('length = ' + s.length);
console.log('END bar()');
}
main(null);
</script>
當
bar()
函數傳入參數
null
時,代碼會報錯,錯誤會向上抛給調用方
foo()
函數,
foo()
函數沒有
try ... catch
語句,是以錯誤繼續向上抛給調用方
main()
函數,
main()
函數有
try ... catch
語句,是以錯誤最終在
main()
函數被處理了。
2、異步錯誤處理
編寫JavaScript代碼時,要時刻牢記,JavaScript引擎是一個事件驅動的執行引擎,代碼總是以單線程執行,而回調函數的執行需要等到下一個滿足條件的事件出現後,才會被執行。
例如,
setTimeout()
函數可以傳入回調函數,并在指定若幹毫秒後執行:
<script>
function printTime() {
console.log('It is time!');
}
setTimeout(printTime, 1000);
console.log('done');
</script>
上面的代碼會先列印
done
,1秒後才會列印
It is time
!。
如果
printTime()
函數内部發生了錯誤,我們試圖用try包裹
setTimeout()
是無效的:
<script>
function printTime() {
throw new Error();
}
try {
setTimeout(printTime, 1000);
console.log('done');
} catch (e) {
console.log('error');
}
</script>
原因就在于調用
setTimeout()
函數時,傳入的
printTime
函數并未立刻執行!緊接着,JavaScript引擎會繼續執行
console.log('done')
;語句,而此時并沒有錯誤發生。直到1秒鐘後,執行
printTime
函數時才發生錯誤,但此時除了在
printTime
函數内部捕獲錯誤外,外層代碼并無法捕獲。
是以,涉及到異步代碼,無法在調用時捕獲,原因就是在捕獲的當時,回調函數并未執行。
類似的,當我們處理一個事件時,在綁定事件的代碼處,無法捕獲事件處理函數的錯誤。
例如,針對以下的表單:
<form>
<input id="x"> + <input id="y">
<button id="calc" type="button">計算</button>
</form>
給button綁定click事件:
<script>
var $btn = $('#calc');
// 取消已綁定的事件:
$btn.off('click');
try {
$btn.click(function () {
var
x = parseFloat($('#x').val()),
y = parseFloat($('#y').val()),
r;
if (isNaN(x) || isNaN(y)) {
throw new Error('輸入有誤');
}
r = x + y;
alert('計算結果:' + r);
});
} catch (e) {
alert('輸入有誤!');
}
</script>
内容 | 網址 |
---|---|
JavaScript個人學習筆記總結 - 快速入門 | https://blog.csdn.net/weixin_50594210/article/details/115112096 |
JavaScript個人學習筆記總結 - 函數 | https://blog.csdn.net/weixin_50594210/article/details/115113081 |
JavaScript個人學習筆記總結 - 标準對象 | https://blog.csdn.net/weixin_50594210/article/details/115112683 |
JavaScript個人學習筆記總結 - 面向對象程式設計 | https://blog.csdn.net/weixin_50594210/article/details/115113024 |
JavaScript個人學習筆記總結 - 浏覽器 | https://blog.csdn.net/weixin_50594210/article/details/115113131 |
JavaScript個人學習筆記總結 - jQuery | https://blog.csdn.net/weixin_50594210/article/details/115113299 |
JavaScript個人學習筆記總結 - 錯誤處理 | https://blog.csdn.net/weixin_50594210/article/details/115113442 |
JavaScript個人學習筆記總結 - underscore | https://blog.csdn.net/weixin_50594210/article/details/115113498 |