這是為了讓程式不會發生不預期的例外 (開發時沒有想到的錯誤),顧而導致程式停止執行的情境,這時候就要靠例外處理try... catch... finally
指令。
在應用程式處理時常常會碰到一些問題及錯誤,用我自身曾經發生的例子來講,例如「物件型態的資料使用陣列的方法」、「在撰寫一個函式時,要傳的參數未定義」等等開發過程中沒想到的錯誤 (例外)。
這時候如果沒有使用例外處理的try... catch... finally
指令,則該程式執行到有問題的程式碼時就會發生例外而造成程式無法執行。使用例外處理後,若是在try
區塊中發生例外,哪程式也會繼續執行catch
區塊的內容,就可以確保一定會執行接下來的程式。
try... catch... finally
指令try {
例外尚未發生時執行的程式 (區塊)
} catch(用以接收及保存外資訊的變數) {
例外發生時執行的程式 (區塊)
} finally {
無論是否有發生例外,最後都會執行的程式 (區塊)
}
Example:
const i = 1
try {
data = i * j // 例外發生,因為使用了一個未宣告的 j
} catch(e) {
console.log(e.message)
} finally {
console.log('Finally')
}
由上述的範例可以得知幾點:
try
區塊發生錯誤,則會立即中斷try
程式的執行,並且將控制權交給catch
區塊並立即執行catch
區塊的程式。反之,若try
區塊中的程式碼沒有任何錯誤,則會忽略掉catch
區塊的程式。catch
區塊的Error
物件 (此處是變數e
,通常也會有人使用e
)。所以可以利用Error
物件提供的name
、message
屬性來顯示錯誤名稱及資訊。finally
區塊不需要則可以整個省略掉。Example:
function name(value) {
try {
console.log(value)
return 'result'
} catch(e) {
console.log(e.message)
} finally {
console.log('Finally')
}
}
console.log(name('hello'))
/*
hello
Finally
result
*/
由上述的範例可以得知一點:
try
區塊有使用到return
這個關鍵字,則finally
區塊的程式就會在哪執行。Example:
let count = 0
function value() {
try {
return count;
} catch(e) {
console.log(e.message)
} finally {
count++;
}
}
console.log(value()) // 0
console.log(count) // 1
由上述的範例可以得知一點:
finally
區塊之前被放入佇列。throw
指令throw new Error(錯誤訊息)
在這裡有幾點要特別注意的是:
throw 'Something is wrong !'
,就是直接拋出一個單純的字串來做顯示,但絕對不建議這麼做。在使用Error
物件的好處於,JavaScript 會自動加上一個堆疊軌跡的的屬性,它可以對目前Error
物件發生的程式碼,列出相對應的呼叫追蹤,透過這樣的方式,我們可以很快地找出是哪一段的程式碼所造成的錯誤。所以最簡單的方式是使用內建的Error()
建構器。throw
語句會拋出程式開發者自訂的例外,throw
會中斷程式執行,其行為就跟 function 裡的return
語句一樣,乘上點所說,在一般使用上都會直接使用Error
物件,請看以下範例。Example:
const calcNumber = (number) => {
if (typeof number !== 'number') throw new Error("number isn't number");
return number
}
console.log(calcNumber('5'))
在 JavaScript 中,依據不同的例外原因可以替換不同的Error
物件,大致可分為 6 種不同的物件,請看以下說明:
eval()
使用,但是這是一個不建議使用的方法,因此,幾乎不會用到。eval()
有關係。另外,這裡再來介紹跟錯誤 (errors) 的特性:
try... catch
& JSON.parse
通常try...catch
會用在哪些情況 !? 會搭配在例外產生時,或是直接丟出例外的方法上,很多情況這些都是 JavaScript 內建的,也可以是程式開發者自己設計的。以目前專案碰到的JSON.parse
這個內建的用於解析 JSON 格式字就對應的物件,範例如下:
Example:
function parse(cell) {
let dataFormat;
try {
dataFormat = JSON.parse(cell);
} catch(e) {
console.log(e);
dataFormat = null;
}
return dataFormat;
}
console.log(parse('{"_EDI_PLATFORM_KEY": "TSXGZ548745"}'))
try... catch
只能捕獲同步錯誤通常在與後端構通時,都是透過 API 互叫,這是一個非同步的程式,哪如果非同步的程式發生錯誤,對try
區塊而言是無法捕獲錯誤的,因為try
區塊內的程式已經執行完畢,非同步的程式是發生於try
區塊之後,範例如下:
Example:
const test = () => {
setTimeout(() => {
throw new Error('Something is wrong !');
}, 2000)
}
try {
test();
console.log('try block');
} catch(e) {
console.log(e.message)
} finally {
console.log('Finally');
}
/*
'try block'
'Finally'
'Something is wrong !'
/*
以上述的範例可以得知幾點:
try
區塊內的'try block'
字樣,接著執行到finally
區塊會印出'Finally'
字樣,最後等到 test function 的計時器 2 秒之後,在拋出錯誤'Something is wrong !'
,像這種情境不是我們要的。async
與await
語法,這樣後面的任務就會等到前面的任務完後才繼續。Example:
const test = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('test function')
},2000)
})
}
const asyncFunction = async () => {
let result;
try {
result = await test();
console.log(result);
console.log('try block');
} catch(e) {
console.log(e.message);
} finally {
console.log('Finally');
}
}
asyncFunction()
/*
'test function'
'try block'
'Finally'
*/
例外處理並不是一個萬靈藥,有時候不使用例外來處理錯誤,直接讓程式直接壞掉,用來提醒開發者有 Bug 這也是一個方法,要看情境。
透過這個章節的教學,可以學到幾個方向。
try... catch... finally
。throw
語句與new Error
建構函式的搭配使用。Error
物件。