본문 바로가기
모던 자바스크립트 튜토리얼

[SOPT]JS 스터디 6주차 에러 핸들링, 프로미스, async await

by 치우치지않는 2023. 5. 27.

try catch

try catch 는 동기적으로 동작한다. 따라서 setTimeout 과 같은 비동기 함수에서 발생한 예외는 try catch 가 잡을 수 없다. setTimeout 은 엔진이 try catch 를 지나간 다음에 실행되기 때문이다. 

따라서 만약 이와 같은 비동기 함수의 예외를 잡고 싶다면, try catch 를 함수 내부에 구현해야 한다. 

try { setTimeout(function() { noSuchVariable; // 스크립트는 여기서 죽습니다. }, 1000); } catch (e) { alert( "작동 멈춤" ); }

-> 에러를 잡지 못한다. 

setTimeout(function() {
  try {
    noSuchVariable; // 이제 try..catch에서 에러를 핸들링 할 수 있습니다!
  } catch {
    alert( "에러를 잡았습니다!" );
  }
}, 1000);

-> 에러를 잡을 수 있다.

throw 연산자

만약 엔진에서는 에러로 처리되지 않지만, 에러로 만들어야 하는 상황이 있다면 인위적으로 에러를 만들 수 있다. 

let json = '{ "age": 30 }'; // 불완전한 데이터

try {

  let user = JSON.parse(json); // <-- 에러 없음

  if (!user.name) {
    throw new SyntaxError("불완전한 데이터: 이름 없음"); // (*)
  }

  alert( user.name );

} catch(e) {
  alert( "JSON Error: " + e.message ); // JSON Error: 불완전한 데이터: 이름 없음
}

에러 다시 던지기

하나의 catch 에서 모든 에러를 잡는 것은 효율적인 디버깅을 방해한다. 따라서 에러를 분리시키는 것이 좋으며 이를 위해 사용되는 것이 에러 다시 던지기이다. 

function readData() {
  let json = '{ "age": 30 }';

  try {
    // ...
    blabla(); // 에러!
  } catch (e) {
    // ...
    if (!(e instanceof SyntaxError)) {
      throw e; // 알 수 없는 에러 다시 던지기
    }
  }
}

try {
  readData();
} catch (e) {
  alert( "External catch got: " + e ); // 에러를 잡음
}

프로미스

프로미스는 .then 을 이용한 프로미스 체이닝이 가능하다. 만약 .then 에서 핸들러가 프로미스를 생성하거나 반환한다면, 이에 이어지는 핸들러는 프로미스가 처리될 때까지 기다리게 된다. 이를 통해 비동기 작업 체이닝이 가능해진다. 

프로미스에서의 에러 핸들링

프로미스에서의 에러 핸들링은 resolve 와 reject 를 통해 이루어진다. 

new Promise((resolve, reject) => {
  resolve("OK");
}).then((result) => {
  blabla(); // 존재하지 않는 함수
}).catch(alert); // ReferenceError: blabla is not defined

프로미스 API

promise.all

Promise.all에 전달되는 프라미스 중 하나라도 거부되면, Promise.all이 반환하는 프라미스는 에러와 함께 바로 거부된다.

promise.allSettled

Promise.allSettled는 모든 프라미스가 처리될 때까지 기다리므로 하나의 요청이 실패해도 다른 요청 결과를 받아올 수 있다.

promise.race

promise.all 과 비슷하나 프로미스의 에러를 반환한다.

promise.resolve, promise.reject

resolve 를 사용하면 캐시된 내용을 프로미스로 만들어 반환값이 항상 프로미스가 되게 한다.

reject 는 결과값이 error 인 거부 상태  프로미스를 만든다.

 

프로미스화

콜백을 받는 함수를 프라미스를 반환하는 함수로 바꾸는 것

function loadScript(src, callback) { let script = document.createElement('script'); script.src = src; script.onload = () => callback(null, script); script.onerror = () => callback(new Error(`${src}를 불러오는 도중에 에러가 발생함`)); document.head.append(script); } // 사용법: // loadScript('path/script.js', (err, script) => {...})

 

->

 

let loadScriptPromise = function(src) { return new Promise((resolve, reject) => { loadScript(src, (err, script) => { if (err) reject(err) else resolve(script); }); }) } // 사용법: // loadScriptPromise('path/script.js').then(...)

 

async와 await

function 앞에 async를 붙이면 해당 함수는 항상 프라미스를 반환한다. await 는 프로미스가 처리될 때까지 기다린다.

에러 처리는 다음과 같이 try catch 로 수행한다.

async function f() { try { let response = await fetch('http://유효하지-않은-주소'); let user = await response.json(); } catch(err) { // fetch와 response.json에서 발행한 에러 모두를 여기서 잡습니다. alert(err); } } f();

댓글