天天看點

JavaScript個人學習筆記總結 - 錯誤處理錯誤處理

JavaScript個人學習筆記總結 - 錯誤處理錯誤處理
JavaScript個人學習筆記總結 - 錯誤處理錯誤處理
JavaScript個人學習筆記總結 - 錯誤處理錯誤處理
内容 網址
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一定會被執行。

是以,有錯誤發生時,執行流程像這樣:

  1. 先執行

    try { ... }

    的代碼;
  2. 執行到出錯的語句時,後續語句不再繼續執行,轉而執行

    catch (e) { ... }

    代碼;
  3. 最後執行

    finally { ... }

    代碼。

而沒有錯誤發生時,執行流程像這樣:

  1. 先執行

    try { ... }

    的代碼;
  2. 因為沒有出錯,

    catch (e) { ... }

    代碼不會被執行;
  3. 最後執行

    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
JavaScript個人學習筆記總結 - 錯誤處理錯誤處理
JavaScript個人學習筆記總結 - 錯誤處理錯誤處理
JavaScript個人學習筆記總結 - 錯誤處理錯誤處理