이번에는 Error Handling과 Promise와 async,await에 대해서 알아보도록 하겠다. 일부만 정리하였기 때문에 자세하게 알고 싶다면 1부에 적었던 참고사이트를 활용하면 될 것이다🙇🏼
아무리 코드를 잘 짠다고 해도 에러를 발생시킬 수 있다. 원인은 실수, 입력 오류, 잘못된 서버 응답 등 다양하기 때문에 에러가 발생하면 스크립트는 ‘죽고’(즉시 중단되고), 콘솔에 에러가 출력된다. 이 때 Error Handling을 이용하여 스크립트가 죽는 걸 방지하고, 에러를 ‘잡아서(catch)’ 더 합당한 무언가를 할 수 있게 한다.
//기본 문법
try {
// 코드...
// 1. 먼저 try에 해당하는 코드가 실행된다
// 2. 에러가 없다면, try 안의 마지막 줄까지 실행되고, catch 블록은 스킵한다.
} catch (err) {
// 에러 핸들링
// 3. 에러가 있다면, try문의 코드는 중단되고 catch(err) 블록으로 제어 흐름이 넘어간다.
//변수 err에는 무슨 일이 일어났는지에 대한 설명이 담긴 에러 객체를 포함한다.
}
에러를 직접 만들 수 있다. 이론상으론, throw 인수에 모든 것을 넘길 수 있지만, 대개 내장 Error 클래스를 상속받은 에러 객체를 인수에 넘긴다.
//JSON.parse의 에러 종류
try {
JSON.parse("{ 잘못된 형식의 json o_O }");
} catch(e) {
alert(e.name); // SyntaxError
alert(e.message); // JSON Parse error: Unrecognized token '잘'
}
//JSON 에러 throw로 처리하는 예시
let json = '{ "age": 30 }'; // name이 없는 불완전한 데이터
try {
let user = JSON.parse(json); // <-- 에러 없음
if (!user.name) {
//JSON Parse의 error 종류는 SyntaxError였기 때문
throw new SyntaxError("불완전한 데이터: 이름 없음");
}
alert( user.name );
} catch(e) {
alert( "JSON Error: " + e.message ); // JSON Error: 불완전한 데이터: 이름 없음
}
⭐️try..catch는 오직 런타임 에러에만 동작한다
⭐️try..catch는 동기적으로 동작한다.
⭐️ 에러 객체가 필요 없으면 catch(err) { 대신 catch {를 쓸 수 있다.
⭐️try..catch는 finally를 이용하여 확장할 수 있다try { ... 코드를 실행 ... } catch(e) { ... 에러 핸들링 ... } finally { ... 항상 실행 ... } // ‼️try..catch..finally 안의 변수는 지역 변수‼️ // ‼️finally 절은 try..catch 절을 빠져나가는 어떤 경우에도 실행‼️ /* finally 안의 코드가 실행되고 난 후, try값이 바깥 코드가 반환됨 (return이 try블록 안에 있는 경우)*/
1️⃣ catch가 모든 에러를 받는다.
2️⃣ catch(err) {...} 블록 안에서 에러 객체 err를 분석한다. 이 때 에러 타입을 instanceof 명령어로 체크한다.
3️⃣ 에러 처리 방법을 알지 못하면 throw err를 해서 에러를 다시 던진다.
//에러를 다시 던져 예상치 못한 에러를 처리하기
function readData() {
let json = '{ "age": 30 }'; // 불완전한 데이터
try {
let user = JSON.parse(json);
// if (!user.name) {
// throw new SyntaxError("불완전한 데이터: 이름 없음");
// }
blabla(); // 예상치 못한 에러
alert( user.name );
} catch(e) {
if (e instanceof SyntaxError) {
alert( "JSON Error: " + e.message );
} else {
throw e; // 에러 다시 던지기 (*)
}
}
}
try {
readData();
} catch (e) {
alert( "External catch got: " + e ); // 에러를 잡음
}
비동기는 응답과 요청이 동시에 일어나지 않는 걸 의미한다(즉, 요청을 한번에 받고 응답에 대한 결과를 주기 때문에 한번에 여러 작업을 할 수 있다) 동기는 그 반대의 의미를 지닌다. 그림으로 보면 다음과 같이 나타낼 수 있다.
그림 참고자료 : https://liarchild.tistory.com/35
비동기 작업이 맞이할 미래의 완료 또는 실패와 그 결과 값을 나타낸다.
Promise의 상태는 3가지로 분류할 수 있는데 사실상 이행과 거부라고 나타날 수 있다. ➡️ 그 이유는 대기 상태를 지나야 이행 혹은 거부 두 상태 중 하나를 반환하게 되기 때문!
1️⃣ 대기(pending) : 비동기 작업 진행중인 상태, 초기 상태
2️⃣ 이행(fulfilled) : 연산이 성공적으로 완료됨
3️⃣ 거부(rejected) : 연산이 실패함
Promise의 결과에 따라 .then 또는 .catch로 수행할 수 있다.
.then : resolve일 때 수행되며, 다음과 같이 두 함수를 활용할 때는 꼭 return을 해야한다. 그 이유는 return이 .then에 해당하는 Promise를 담당하기 때문이다.
.catch : reject일 때 어떤 곳에 error가 나도 한꺼번에 처리가 가능하다.//.then .catch 사용 예시 .then(postId => { console.log('Post:', postId) return getComments(postId) //생략 .catch(message => console.log(message));
- 어떤 코드가 먼저 실행되었는지 순서를 알기 어려워진다.
→ 에러 원인 불명확
→ 디버깅 어려움
→ 코드 예측성 떨어짐- 코드 중첩
→ 가독성 떨어짐
function 앞에 async 키워드를 추가 할 때 이점
1️⃣ 함수는 언제나 Promise를 반환한다.
2️⃣ 함수 안에서 await를 사용할 수 있다.
Promise 앞에 await 키워드를 붙이면 자바스크립트는 Promise 가 처리될 때까지 대기하게 된다. 처리가 완료되면 조건에 따라 아래와 같은 동작이 이어지게 된다.
1️⃣ 에러 발생 – 예외가 생성됨(에러가 발생한 장소에서 throw error를 호출한 것과 동일함)
2️⃣ 에러 미발생 – Promise 객체의 result 값을 반환
async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("완료!"), 1000)
});
let result = await promise; // Promise가 이행될 때까지 기다림 (*)
alert(result); // "완료!"
}
f();