
REST API를 호출할 때 자주 접하게 되는 JavaScript 문법과 패턴을 공부 겸 정리해 보았습니다.
resolve는 성공, reject는 실패를 나타냅니다.
const promise = new Promise((resolve, reject) => {
// (1) 비동기 작업 실행…
if (/* 성공 */) {
resolve('작업 결과 데이터'); // fulfilled
} else {
reject(new Error('에러 사유')); // rejected
}
});
// 지금은 pending 상태, 나중에 resolve/reject 호출에 따라 settled 됩니다.
promise
.then(value => {
console.log('이행 결과:', value);
})
.catch(error => {
console.error('거부 이유:', error);
});
.then() 메서드.then() 자체도 항상 새로운 Promise를 반환하므로, 이어서 .then()을 체인(chain) 형태로 연결할 수 있습니다// 사용 예시
fetch('https://api.example.com/users') // Promise 반환 (pending)
.then(response => response.json()) // ① 응답을 JSON으로 파싱
.then(data => {
console.log(data); // ② 파싱된 데이터를 처리
})
.catch(error => {
console.error(error); // ③ 중간에 발생한 에러 처리
});
async/await로 비동기 코드 가독성 높이기Promise 기반 코드를 더 직관적으로 작성할 수 있는 문법입니다.
async 함수return한 값은 자동으로 Promise.resolve()로 래핑됩니다async 키워드를 붙여 선언한 함수는 항상 Promise 객체를 반환합니다.return 값;을 사용하면, 마치 아래 코드처럼 자동으로 Promise.resolve(값)을 반환하는 효과를 냅니다. // 암묵적 래핑 예시
async function foo() {
return 123;
// → 내부적으로는 return Promise.resolve(123);과 같습니다.
}
foo().then(value => {
console.log(value); // 123
});
// 명시적 래핑 예시
function fooExplicit() {
return Promise.resolve(123);
}
fooExplicit().then(value => {
console.log(value); // 123
});
async function foo() {
return 123;
// → 내부적으로 Promise.resolve(123)을 반환합니다.
}
foo().then(value => console.log(value)); // 123
await 키워드Promise가 이행될 때까지 함수 실행을 일시 중단throw를 발생시켜 catch 블록으로 전달async function fetchUsers() {
try {
const response = await fetch('https://api.example.com/users');
if (!response.ok) {
// HTTP 상태 코드가 200~299가 아니면 예외 처리 추가
throw new Error(`HTTP 에러: ${response.status}`);
}
const users = await response.json(); // JSON 파싱 대기
return users;
} catch (error) {
console.error('사용자 목록 로드 실패:', error);
throw error; // 필요 시 다시 던져 호출 측에서 추가 처리
}
}
// 호출 예
fetchUsers()
.then(users => console.log('사용자 목록:', users))
.catch(err => console.error('최종 에러 처리:', err));
.then(), async/await와 함께 사용합니다.async/await 버전)async function getUsers() {
try {
const res = await fetch('https://api.example.com/users', {
method: 'GET',
headers: {
'Accept': 'application/json'
}
});
if (!res.ok) {
throw new Error(`HTTP 에러: ${res.status}`); // 상태 코드 검사 추가
}
const users = await res.json();
console.log('사용자 데이터:', users);
} catch (error) {
console.error('네트워크 또는 파싱 오류:', error);
}
}
getUsers();
async function createPost(title, content) {
try {
const payload = { title, content };
const res = await fetch('https://api.example.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json' // JSON 전송을 위한 필수 헤더
},
body: JSON.stringify(payload) // 객체를 문자열로 변환
});
if (!res.ok) {
throw new Error(`HTTP 에러: ${res.status}`);
}
const result = await res.json();
console.log('생성된 게시글:', result);
} catch (error) {
console.error('게시글 생성 실패:', error);
}
}
createPost('제목 예시', '내용 예시');
try/catch, .catch(), .finally()try 블록 안에서 동기적 예외(throw)나, await로 기다린 Promise 거부(reject)가 발생하면 즉시 catch 블록으로 넘어갑니다..catch()는 Promise에서 발생한 에러를 잡습니다..finally() 블록을 쓰면 성공·실패와 상관없이 항상 마지막에 실행됩니다.Promise 체인에서
fetch('/api/data')
.then(res => {
if (!res.ok) throw new Error(`상태 코드: ${res.status}`);
return res.json();
})
.catch(err => console.error('파싱 오류 또는 네트워크 오류:', err))
.finally(() => console.log('작업 완료'));
async/await 내부에서
async function loadData() {
try {
const res = await fetch('/api/data');
if (!res.ok) throw new Error(`HTTP 에러: ${res.status}`);
const data = await res.json();
console.log(data);
} catch (error) {
console.error('데이터 로드 실패:', error);
} finally {
console.log('loadData() 종료');
}
}
loadData();
Fetch 이전에 쓰이던 콜백 기반 API로, HTTP 세부 처리 단계 (준비 → 전송 → 응답)를 직접 제어할 수 있습니다.
const xhr = new XMLHttpRequest(); // ① 객체 생성
xhr.open('GET', 'https://api.example.com/users'); // ② HTTP 메서드·URL 설정
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
const data = JSON.parse(xhr.responseText); // ③ JSON 파싱
console.log('데이터:', data);
} else {
console.error('상태 코드 오류:', xhr.status);
}
}
};
xhr.onerror = () => console.error('네트워크 오류 발생'); // ④ 네트워크 에러
xhr.send(); // ⑤ 요청 전송
this 바인딩이 주변 스코프와 같습니다.// 일반 함수
fetch(url).then(function(response) {
return response.json();
});
// Arrow 함수
fetch(url).then(response => response.json());
${})${}로 간편하게 삽입합니다.const userId = 42;
const url = `https://api.example.com/users/${userId}`; // 변수 삽입
console.log(`요청 URL: ${url}`);
// 객체 분해
const user = { id: 1, name: 'Alice', age: 30 };
const { name, age } = user; // name과 age만 변수로 추출
console.log(name, age);
// 배열 분해
const arr = [10, 20, 30];
const [first, , third] = arr; // 두 번째 요소는 건너뜀
console.log(first, third);
...obj or ...arr): 배열·객체를 펼쳐서 복사하거나 합칠 때 사용function(...args) or const [a, ...rest]): 나머지 요소를 한 곳에 모아 배열 또는 객체로 받을 때 사용...)**// 배열에서의 사용 예제**
const arr1 = [1, 2, 3];
// 배열 복사
const copy = [...arr1];
// 👉 copy는 [1, 2, 3] (arr1과 별개 메모리)
/* 출력 확인 */
console.log('원본:', arr1);
console.log('복사본:', copy);
// 배열 합치기
const arr2 = [4, 5];
const merged = [...arr1, ...arr2];
// 👉 merged는 [1, 2, 3, 4, 5]
console.log('합쳐진 배열:', merged);
// 객체에서의 사용 예제
const defaults = { method: 'GET', headers: { Accept: 'application/json' } };
const options = { headers: { 'Content-Type': 'application/json' }, cache: 'no-cache' };
// 객체 병합 (뒤에 나온 프로퍼티가 앞을 덮어씀)
const config = { ...defaults, ...options };
/*
config는 {
method: 'GET',
headers: { 'Content-Type': 'application/json' }, // defaults.headers는 덮어써짐
cache: 'no-cache'
}
*/
console.log('병합 결과:', config);
// 프로퍼티 추가·수정
const updated = { ...config, method: 'POST', timeout: 5000 };
/*
updated는 {
method: 'POST', // 원래 method GET에서 POST로 수정
headers: { 'Content-Type': 'application/json' },
cache: 'no-cache',
timeout: 5000 // 새로 추가된 프로퍼티
}
*/
console.log('수정 결과:', updated);
...)// 함수 매개변수에서의 사용 예제
// 첫 번째 인자 url은 고정, 나머지 인자는 모두 middlewares 배열에 담김
function request(url, ...middlewares) {
console.log('요청 URL:', url);
console.log('미들웨어 개수:', middlewares.length);
console.log('미들웨어 목록:', middlewares);
}
const mw1 = () => {}, mw2 = () => {}, mw3 = () => {};
request('/api/users', mw1, mw2, mw3);
/* 출력:
요청 URL: /api/users
미들웨어 개수: 3
미들웨어 목록: [mw1, mw2, mw3]
*/
// 배열 분해할당에서의 사용 예제
const numbers = [10, 20, 30, 40, 50];
// 첫 번째 요소만 first에, 나머지는 restNums 배열에 모음
const [first, ...restNums] = numbers;
console.log('첫 번째:', first); // 10
console.log('나머지 배열:', restNums); // [20, 30, 40, 50]
// 객체 분해할당에서의 사용 예제
const user = { id: 1, name: 'Alice', age: 30, city: 'Seoul' };
// id와 name은 각각 변수에, 나머지 프로퍼티는 others 객체에 모음
const { id, name, ...others } = user;
console.log('id:', id); // 1
console.log('name:', name); // Alice
console.log('others:', others); // { age: 30, city: 'Seoul' }
undefined일 때 기본값을 사용합니다.function fn(x = 10) {
console.log(x);
}
fn(); // 10
function fetchData(url, options = { method: 'GET' }) {
return fetch(url, options);
}
fetchData('/api'); // options는 { method: 'GET' }
JSON.stringify: JS 객체를 JSON 문자열로 변환JSON.parse: JSON 문자열을 JS 객체로 변환const str = JSON.stringify({ a: 1 });
const obj = JSON.parse(str);
console.log(str) // {"a":1}
console.log(obj) // { a: 1 }
const bodyObj = { title: '안녕하세요', content: 'REST API 예제' };
const bodyText = JSON.stringify(bodyObj); // 문자열화
fetch('/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: bodyText,
})
.then(res => res.json())
.then(data => {
// 서버 응답이 JSON이면 자동 파싱
console.log(data);
});
URLSearchParams는 URL의 쿼리 문자열(예: ?key1=값1&key2=값2)을 생성·조작·파싱할 수 있게 해 주는 Web API입니다.const params = new URLSearchParams({ page: 1, limit: 20 });
const url = `https://api.example.com/items?${params.toString()}`;
fetch(url)
.then(res => res.json())
.then(data => console.log(data));
multipart/form-data 형태로 데이터 구성에 사용합니다.const form = new FormData();
form.append('username', 'kim');
form.append('avatar', fileInput.files[0]);
fetch('/upload', {
method: 'POST',
body: form, // Content-Type은 자동 설정
})
.then(res => res.json())
.then(result => console.log(result));
null 또는 undefined면 undefined를 반환하고 에러를 방지합니다.const response = { data: { user: null } };
console.log(response.data.user?.name); // 에러 없이 undefined 반환
null 또는 undefined일 때만 우측 값을 사용합니다.const token = response.token ?? '토큰없음';
console.log(token);
Promise.all() (병렬 Promise 실행)const req1 = fetch('/api/a').then(r => r.json());
const req2 = fetch('/api/b').then(r => r.json());
Promise.all([req1, req2])
.then(([resA, resB]) => {
console.log('A 결과:', resA);
console.log('B 결과:', resB);
})
.catch(err => console.error('하나라도 실패:', err));