에러 처리와 로딩 상태
실패했을 때와 기다리는 동안의 화면을 만듭니다.
기다리는 동안과 실패했을 때
앞 단원의 예제는 출력 칸에 결과만 냈습니다. 실제 화면은 세 가지 상태를 모두 보여 주어야 합니다.
- 기다리는 중 — 요청을 보냈고 아직 오지 않았습니다.
- 받았음 — 데이터를 화면에 그립니다.
- 실패 — 무엇이 잘못됐는지 알리고, 다시 해 볼 길을 줍니다.
이 셋을 빠뜨리면 사용자는 빈 화면을 보고 고장 났다고 여깁니다. 4부의 DOM 다루기와 5부의 비동기를 여기서 합칩니다.
세 상태를 화면에 내기
실행한 뒤 미리보기 탭을 열어 보세요. 상태에 따라 모양이 다릅니다.
const box = document.querySelector("#box"); async function load(id) { box.textContent = "불러오는 중..."; box.className = "loading"; try { const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${id}`); if (!response.ok) { throw new Error(`서버가 ${response.status} 를 돌려주었습니다`); } const todo = await response.json(); box.textContent = todo.title; box.className = "done"; } catch (error) { box.textContent = `불러오지 못했습니다: ${error.message}`; box.className = "error"; } } await load(1); console.log(box.className); console.log(box.textContent);
load(99999) 로 고쳐 실행하면 실패 화면을 볼 수
있습니다.
실패한 경우
const box = document.querySelector("#box"); try { const response = await fetch("https://jsonplaceholder.typicode.com/todos/99999"); if (!response.ok) { throw new Error(`서버가 ${response.status} 를 돌려주었습니다`); } box.textContent = "받았습니다"; box.className = "done"; } catch (error) { box.textContent = `불러오지 못했습니다: ${error.message}`; box.className = "error"; } console.log(box.className); console.log(box.textContent);
오류 메시지를 그대로 보여 주지 마세요. 사용자는
TypeError: Failed to fetch 를 읽을 수 없습니다.
무엇을 해야 하는지 알려 주는 문구로 바꿔 적습니다.
끝나면 반드시 하는 일
성공이든 실패든 로딩 표시는 꺼야 합니다. 두 자리에 똑같이 적는 대신
finally 에 한 번만 적습니다(5.3 · 5.4).
const spinner = document.querySelector("#spinner"); const box = document.querySelector("#box"); try { const response = await fetch("https://jsonplaceholder.typicode.com/todos/2"); const todo = await response.json(); box.textContent = todo.title; } catch (error) { box.textContent = "잠시 뒤에 다시 시도해 주세요"; } finally { spinner.className = "off"; } console.log(spinner.className); console.log(box.textContent);
여러 요청을 함께
const [first, second] = await Promise.all([ fetch("https://jsonplaceholder.typicode.com/todos/1").then(r => r.json()), fetch("https://jsonplaceholder.typicode.com/todos/2").then(r => r.json()) ]); console.log(first.title); console.log(second.title);
Promise.all 은 하나라도 실패하면 통째로
실패합니다. 일부가 실패해도 나머지를 쓰고 싶다면
Promise.allSettled 를 사용합니다.
처음에 자주 걸리는 것
실패한 자리에서 return 하면 끄는 줄을
건너뜁니다. finally 에 두면 그럴 일이 없습니다.
개발자에게 필요한 말이지 사용자에게 필요한 말이 아닙니다. 콘솔에는 그대로 남기고 화면에는 다시 해 볼 길을 적으세요.
요청이 끝나기 전에 또 누르면 요청이 겹칩니다. 시작할 때 단추를 잠그고
finally 에서 풉니다.
파트 5 미니 실습 — API 조회 화면
번호를 입력하고 조회 단추를 누르면 그 할 일을 가져와 보여 주는 화면을 만드세요. 아래를 모두 지켜야 합니다.
- 누르면 먼저 불러오는 중을 보여 줍니다.
- 받으면 제목을 그립니다.
- 없는 번호(예: 99999)면 사람이 읽을 수 있는 문구로 알립니다.
- 끝나면 성공이든 실패든 단추를 다시 누를 수 있게 합니다.
try 앞과 finally 에 나눠 두면 빠뜨릴 일이 없습니다.// 위 정답을 여기에 옮겨 적고 실행해 보세요. // 실행한 뒤 미리보기 탭에서 번호를 바꿔 가며 눌러 볼 수 있습니다. console.log("여기에 작성하세요");
여기까지 하면 파트 5 가 끝납니다. 다음 파트에서는 코드를 클래스와 모듈로 나눕니다.
이 단원의 정리
- 기다리는 중 · 받았음 · 실패 세 상태를 모두 화면에 보여 줍니다.
- 로딩 표시를 끄는 일은
finally에 한 번만 적습니다. - 오류 메시지를 그대로 보여 주지 말고 다시 해 볼 길을 적습니다.
- 요청 중에는 단추를 잠가 겹치지 않게 합니다.
Promise.all은 하나라도 실패하면 통째로 실패합니다.