> For the complete documentation index, see [llms.txt](https://mistborn.gitbook.io/til-coding/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mistborn.gitbook.io/til-coding/javascript/error-handling-try..catch.md).

# Error handling, "try..catch"

## The “try…catch” syntax

```javascript
// syntax
try {

  // code...

} catch (err) {

  // error handling

}
```

![](/files/-Lhx3l4pfkHR38u2iEmS)

```javascript
// 沒有錯誤發生
try {

  alert('Start of try runs');  // (1) <--

  // ...no errors here

  alert('End of try runs');   // (2) <--

} catch(err) {

  alert('Catch is ignored, because there are no errors'); // (3)

}

alert("...Then the execution continues");

// 錯誤發生
try {

  alert('Start of try runs');  // (1) <--

  lalala; // error, variable is not defined!

  alert('End of try (never reached)');  // (2)

} catch(err) {

  alert(`Error has occurred!`); // (3) <--

}

alert("...Then the execution continues");

// try..catch 能夠運作的前提是程式碼是有效的程式碼，因為引擎讀不懂程式碼，所以不會執行 try..catch
try {
  {{{{{{{{{{{{
} catch(e) {
  alert("The engine can't understand this code, it's invalid");
}

// 如果有非同步的程式碼，因為已經執行完 try..catch，所以對非同步的 setTimeout 裡的程式碼
// 不會捕捉錯誤
try {
  setTimeout(function() {
    noSuchVariable; // script will die here
  }, 1000);
} catch (e) {
  alert( "won't work" );
}

// 要捕捉 setTimeout 裡程式碼的錯誤，要在裡面加上 try..catch
setTimeout(function() {
  try {
    noSuchVariable; // try..catch handles the error!
  } catch {
    alert( "error is caught here!" );
  }
}, 1000);
```

## Error object

```javascript
// 捕捉到的錯誤，會返回作為 catch 的參數
try {
  // ...
} catch(err) { // <-- the "error object", could use another word instead of err
  // ...
}

// 錯誤物件包含 name message 2 個屬性，還有很多非標準的屬性，最多被廣泛運用的是 stack
try {
  lalala; // error, variable is not defined!
} catch(err) {
  alert(err.name); // ReferenceError
  alert(err.message); // lalala is not defined
  alert(err.stack); // ReferenceError: lalala is not defined at ...

  // Can also show an error as a whole
  // The error is converted to string as "name: message"
  alert(err); // ReferenceError: lalala is not defined
}

```

## Optional “catch” binding

```javascript
// 最近新增的如果不需要錯誤訊息，catch 可以忽略它
try {
  // ...
} catch {
  // error object omitted
}
```

## Using “try…catch”

```javascript
// 實際使用 try..catch 情形
let json = '{"name":"John", "age": 30}'; // data from the server

let user = JSON.parse(json); // convert the text representation to JS object

// now user is an object with properties from the string
alert( user.name ); // John
alert( user.age );  // 30let json = "{ bad json }";

// 用 try..catch 處理錯誤，我們只印出錯誤訊息，但可以做其他處理，
// 发送一个新的网络请求，给用户提供另外的选择，把异常信息发送给记录日志的工具
try {

  let user = JSON.parse(json); // <-- 当这里抛出异常...
  alert( user.name ); // 不工作

} catch (e) {
  // ...跳到这里继续执行
  alert( "Our apologies, the data has errors, we'll try to request it one more time." );
  alert( e.name );
  alert( e.message );
}
```

## Throwing our own errors

```javascript
// 程式碼運行正常，但沒有我們要的 name 屬性。
let json = '{ "age": 30 }'; // incomplete data

try {

  let user = JSON.parse(json); // <-- no errors
  alert( user.name ); // no name!

} catch (e) {
  alert( "doesn't execute" );
}

// 可以用 throw 自定義錯誤
throw <error object>

// syntax，有內建的錯誤建構函式 Error、 SyntaxError、ReferenceError、TypeError 等等
let error = new Error(message);
// or
let error = new SyntaxError(message);
let error = new ReferenceError(message);
// ...

// example，name 屬性是建構函式的名稱，message 屬性來自丟入的參數
let error = new Error("Things happen o_O");

alert(error.name); // Error
alert(error.message); // Things happen o_O

try {
  JSON.parse("{ bad json o_O }");
} catch(e) {
  alert(e.name); // SyntaxError
  alert(e.message); // Unexpected token o in JSON at position 0
}

// 實際使用
let json = '{ "age": 30 }'; // incomplete data

try {

  let user = JSON.parse(json); // <-- no errors

  if (!user.name) {
    throw new SyntaxError("Incomplete data: no name"); // (*)
  }

  alert( user.name );

} catch(e) {
  alert( "JSON Error: " + e.message ); // JSON Error: Incomplete data: no name
}
```

## Rethrowing

```javascript
// 有可能在 try 發生預料之外的異常，這裡拋出 JSON Error 的錯誤是不對的錯誤訊息
let json = '{ "age": 30 }'; // incomplete data

try {
  user = JSON.parse(json); // <-- forgot to put "let" before user

  // ...
} catch(err) {
  alert("JSON Error: " + err); // JSON Error: ReferenceError: user is not defined
  // (no JSON Error actually)
}

// 我們可以通過其他方式知道正確的錯誤訊息
try {
  user = { /*...*/ };
} catch(e) {
  alert(e.name); // "ReferenceError" for accessing an undefined variable
}

// catch 捕捉已知的錯誤，拋出其他未知的錯誤
// rethrowing 的規則，捕捉所有錯誤，catch(err) {...} 處理已知錯誤，未知錯誤 throw err
let json = '{ "age": 30 }'; // 不完整的数据
try {

  let user = JSON.parse(json);

  if (!user.name) {
    throw new SyntaxError("Incomplete data: no name");
  }

  blabla(); // 预料之外的异常

  alert( user.name );

} catch(e) {

  if (e.name == "SyntaxError") {
    alert( "JSON Error: " + e.message );
  } else {
    throw e; // rethrow (*)
  }

}

// 未知的錯誤會被外層 try..catch 處理
function readData() {
  let json = '{ "age": 30 }';

  try {
    // ...
    blabla(); // 异常！
  } catch (e) {
    // ...
    if (e.name != 'SyntaxError') {
      throw e; //  重新抛出（不知道如何处理它）
    }
  }
}

try {
  readData();
} catch (e) {
  alert( "External catch got: " + e ); // 捕获到！
}
```

## try…catch…finally

```javascript
// syntax，不果有沒有錯誤發生 finally 都會執行
try {
   ... try to execute the code ...
} catch(e) {
   ... handle errors ...
} finally {
   ... execute always ...
}

// If you answer “Yes”, then try -> catch -> finally.
// If you say “No”, then try -> finally.
try {
  alert( 'try' );
  if (confirm('Make an error?')) BAD_CODE();
} catch (e) {
  alert( 'catch' );
} finally {
  alert( 'finally' );
}

// 不論有沒有結果都會印出計算時間
let num = +prompt("Enter a positive integer number?", 35)

let diff, result;

function fib(n) {
  if (n < 0 || Math.trunc(n) != n) {
    throw new Error("Must not be negative, and also an integer.");
  }
  return n <= 1 ? n : fib(n - 1) + fib(n - 2);
}

let start = Date.now();

try {
  result = fib(num);
} catch (e) {
  result = 0;
} finally {
  diff = Date.now() - start;
}

alert(result || "error occured");

alert( `execution took ${diff}ms` );

// try..catch 結束執行包含 return，finally 會先被執行，才會執行外部程式碼。
function func() {

  try {
    return 1;

  } catch (e) {
    /* ... */
  } finally {
    alert( 'finally' );
  }
}

alert( func() ); // first works alert from finally, and then this one

// 如果暫時不想處理錯誤，用 try..finally 確保程式執行完畢
function func() {
  // 开始做需要被完成的操作（比如测量）
  try {
    // ...
  } finally {
    // 完成前面要做的事情，即使 try 里面执行失败
  }
}
```

## Global catch

```javascript
// try..catch 之外的程式碼，出現了嚴重錯誤，在瀏覽器環境可以使用 window.onerror 處理
window.onerror = function(message, url, line, col, error) {
  // ...
};

// example，不是去處理所有錯誤，而是提供開發者錯誤訊息
<script>
  window.onerror = function(message, url, line, col, error) {
    alert(`${message}\n At ${line}:${col} of ${url}`);
  };

  function readData() {
    badFunc(); // 哦，出问题了！
  }

  readData();
</script>
```
