Promise의 상태 흐름과 Axios 메서드를 배우고 실습했는데, 정작 가장 크게 배운 건 코드 문법이 아니라
.then/.catch가 에러를 조용히 묻어 사실이었다.
오늘은 ES6의 Promise와 Axios 실습을 진행했다.
Promise는 비동기(client-server) 작업의 처리를 도와주는 객체다.
new Promise((resolve, reject) => {
});
상태(state)는 다음 흐름으로 진행된다.
pending(초기화) → resolve 또는 reject 호출 → fulfilled 또는 rejectedresolve와 reject를 통칭해서 settled라고 부른다result는 undefined로 초기화되고, resolve(value)의 value가 서버의 json data를 담는 콜백 역할을 한다. reject는 error를 담는다.Axios는 script 기반 SPA에서 주로 사용하며, 다음 특징을 정리했다.
.finally(() => {}): 성공/실패 여부와 상관없이 마지막에 무조건 실행됨post는 인캡슐레이션 때문에 xxxx?queryString처럼 쿼리 스트링이 붙지 않음patch는 일부 수정, put은 전체 수정 (리소스 소모가 큼)delete/1처럼 붙는 방식은 path variable 방식img는 textContent가 아니라 src로 지정한다img 태그는 텍스트를 담는 태그가 아니라 이미지 경로를 불러오는 태그이기 때문에, 텍스트를 넣는 textContent 대신 src 속성을 써야 한다는 걸 다시 확인했다.
image.src = object.image;
image.alt = object.title; // 접근성 보완
const/let의 블록 스코프 때문에 생긴 card is not definedforEach 콜백 안에서 const card를 선언해놓고, card.appendChild(...)는 콜백 밖에서 호출하는 실수를 했다. const/let은 블록 스코프이기 때문에, forEach 콜백이 끝나는 순간 그 안에서 만든 변수는 전부 사라진다. 카드 생성 → 조립 → appendChild까지 전부 forEach 콜백 안에서 끝내야 한다. // 잘못된 예
ary.forEach((object, idx) => {
const card = document.createElement('div');
// ...
});
card.appendChild(image); // card는 이미 스코프 밖
3. .then/.catch 체인이 오타로 인한 에러를 가리는 문제
response를 respose로 오타 낸 것이었다.이 부분은 AI를 사용하기 전까지 계속 문제를 찾아내지 못하고 있었다..then(response => {
ary = respose.data; // response 아니라 respose (오타)
})
.catch(error => {
console.log(`debug >>>> error ${error}`);
});
respose는 정의되지 않은 변수라 ReferenceError가 발생하는데, 바로 뒤에 연결된 .catch()가 이 에러를 조용히 넘겨받아버려서 화면에는 빨간 에러가 전혀 뜨지 않았다. 콘솔에 debug >>>> error ... 로그만 조용히 찍히고 지나갔다.여기서 얻은 깨달음은, "화면에 에러가 안 뜬다 = 코드가 정상이다"는 아니라는 것이다.
.then안의 모든 에러(오타 포함)는.catch로 넘어가므로, 콘솔 로그를 항상 확인하는 습관이 필요하다는 것을 느꼈다.
그런데 막상 생각해보니 콘솔로그 에러를 제대로 읽는 방법에 대해 공부해본 적이 없었다..
4. e.target을 e.targer로 오타 냈을 때의 에러 읽는 법
Uncaught TypeError: Cannot read properties of undefined (reading 'textContent')
이 메시지를 뒤에서부터 읽으면 원인을 역추론할 수 있다.
'textContent'를 읽으려 했다 → 무언가.textContent를 쓴 코드를 찾는다undefined였다 → e.targer.textContent에서 e.targer가 undefinede(이벤트 객체)에는 target은 있어도 targer는 없다 → 오타 확정Cannot read properties of undefined/null (reading 'xxx') 형태의 에러는 대부분 아래 셋 중 하나가 원인이었다.
| 원인 | 예시 |
|---|---|
| 오타 | e.targer (target 아님) |
| DOM에 없는 요소를 선택 | querySelector('#없는id') → null 반환 |
| 비동기 데이터가 아직 안 옴 | fetch 응답 오기 전에 배열 순회 |
앞으로 더 나은 이슈 해결을 위해 js 에러를 읽는 md파일을 만들었다!


직접 해본 것
fakestoreapi.com/products에서 상품 데이터 받아와 카드 UI로 렌더링splice + 재호출)id 사용 방식 / handler 사용 방식 구분결과
오타와 스코프 문제를 전부 수정한 뒤에는 정상적으로 상품 목록이 카드 형태로 렌더링되었다.
const loadData = async () => {
await axios.get('https://fakestoreapi.com/products')
.then(response => {
ary = response.data;
})
.catch(error => {
console.error(error);
});
};
const makeProduct = () => {
container.innerHTML = '';
ary.forEach((object, idx) => {
const card = document.createElement('div');
card.className = 'card';
const image = document.createElement('img');
image.src = object.image;
image.alt = object.title;
const title = document.createElement('h3');
title.textContent = object.title;
const price = document.createElement('p');
price.textContent = object.price;
const delBtn = document.createElement('button');
delBtn.className = 'btn';
delBtn.textContent = '삭제';
delBtn.onclick = () => {
ary.splice(idx, 1);
makeProduct();
};
card.appendChild(image);
card.appendChild(title);
card.appendChild(price);
card.appendChild(delBtn);
container.appendChild(card);
});
};
막힌 부분
가장 오래 붙잡고 있었던 건 respose.data 오타였다. 콘솔에 빨간 에러가 뜨지 않아서 한참을 "왜 데이터가 안 그려지지?"라며 렌더링 로직 쪽만 들여다봤다.
★ 해결 방법
respose → response 오타 수정.catch(error => console.error(error))처럼 에러를 눈에 띄게 로깅이번 실습을 계기로 에러 메시지를 읽는 순서도 정리했다.
TypeError / ReferenceError / SyntaxError)console.log()로 실제 값 찍어서 확인.then/.catch 대신 try/catch + async/await 조합으로 에러 처리 다시 연습