🧠 핵심 개념
전통적인 비동기 방식: 콜백 지옥
fs.readFile('file.txt', (err, data) => {
if (err) return console.error(err);
console.log(data);
});
프로미스 기반
fs.promises.readFile('file.txt')
.then(data => console.log(data))
.catch(err => console.error(err));
✅ async/await 기반 (가장 가독성 좋음)
async function readFile() {
try {
const data = await fs.promises.readFile('file.txt');
console.log(data);
} catch (err) {
console.error(err);
}
}
✅ 요약
async | 이 함수 안에서 await 쓸 거야 |
await | 비동기 작업이 끝날 때까지 기다릴게. 이후에 무조건 promise로 반환된 값이 와야해. |
Promise | 비동기 작업 결과를 담는 객체 |
🧠 Promise란?
Promise는 **"미래에 결과를 제공할 수 있는 객체"**입니다.
성공 또는 실패 결과를 나중에 한 번만 전달해주는 약속(promise) 같은 거예요.
📦 구조
const promise = new Promise((resolve, reject) => {
// 비동기 작업 실행
if (성공) {
resolve(값); // 성공 시
} else {
reject(에러); // 실패 시
}
});
✅ 예제: 1초 후 "끝"을 출력하는 Promise
function wait(ms) {
return new Promise((resolve) => {
setTimeout(() => {
resolve('끝!');
}, ms);
});
}
wait(1000).then((result) => {
console.log(result); // 1초 후에 "끝!" 출력됨
});
🪄 왜 좋은가?
기존의 콜백 지옥을 피할 수 있기 때문입니다.
❌ 콜백 지옥 예시
getUser(id, (user) => {
getPosts(user.id, (posts) => {
getComments(posts[0].id, (comments) => {
// 너무 깊어짐
});
});
});
✅ Promise로 개선
getUser(id)
.then(user => getPosts(user.id))
.then(posts => getComments(posts[0].id))
.then(comments => {
// 훨씬 깔끔함
})
.catch(err => console.error(err));
📌 상태 3가지
Promise는 항상 3가지 상태 중 하나를 가집니다:
pending | 대기 중 (아직 결과 없음) |
fulfilled | resolve() 호출됨 (성공) |
rejected | reject() 호출됨 (실패) |
🔄 그리고 async/await은…
const result = await wait(1000); // 내부적으로 .then()을 기다림
await는 사실상 promise.then(...)을 동기 코드처럼 보이게 하는 문법이에요.
💡 간단한 예제
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function main() {
console.log("1초 기다리는 중...");
await wait(1000); // 1초 대기
console.log("끝났어요!");
}
main();
실행 결과:
(1초 후)
끝났어요!
만약 async await를 사용하지 않는다면
function wait(ms) {
return setTimeout(ms);
}
function main() {
console.log("1초 기다리는 중...");
wait(1000); // 1초 대기
console.log("끝났어요!");
}
main();
실행 결과:
끝났어요!
(1초 후)
🧩 어떤 함수들이 Promise 콜백에 들어갈 수 있을까?
✅ 대표적인 콜백 기반 함수들:
이들은 기본적으로 콜백을 인자로 받아서 처리하므로 Promise로 감싸서 사용할 수 있어요.
setTimeout() | 일정 시간 후 실행 |
setInterval() | 일정 주기 반복 실행 (보통 clearInterval()과 함께 씀) |
fs.readFile() (Node.js) | 파일 읽기 |
fs.writeFile() (Node.js) | 파일 쓰기 |
navigator.geolocation.getCurrentPosition() (브라우저) | 위치 정보 요청 |
XMLHttpRequest (구버전) | HTTP 요청 |
child_process.exec() (Node.js) | 셸 명령 실행 |
🧪 예시: fs.readFile()을 Promise로 감싸기
const fs = require('fs');
function readFilePromise(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, 'utf8', (err, data) => {
if (err) reject(err); else resolve(data);
});
});
}
🎁 팁: 요즘은 Promise 버전이 따로 있어요
많은 API가 이미 Promise 버전이 존재합니다:
fetch() | 브라우저의 HTTP 요청 (Promise 기반) |
fs.promises.readFile() | Node.js의 Promise 버전 |
mysql2/promise | MySQL 모듈의 Promise 버전 |
axios.get() | Axios는 내부적으로 Promise 사용 |
참고로! 하위에서 async로 비동기처리를 해주었다면, 그 상위 함수들에서도 모두 async로 기다려줘야해요
// 가장 하위 함수 (Promise 반환)
function daughter() {
return new Promise((resolve) => {
setTimeout(() => {
console.log('👧 daughter: 일 끝났어!');
resolve('결과 from daughter');
}, 1000);
});
}
// 중간 함수 (async 함수로 daughter 호출)
async function mother() {
console.log('👩 mother: daughter에게 부탁할게.');
const result = await daughter();
console.log(`👩 mother: daughter가 준 결과 -> ${result}`);
return `mother가 받은: ${result}`;
}
// 최상위 함수 (async 함수로 mother 호출)
async function grandmother() {
console.log('👵 grandmother: mother에게 부탁할게.');
const finalResult = await mother();
console.log(`👵 grandmother: 최종 결과 -> ${finalResult}`);
}
// 실행
grandmother();
'C Lang > JS Basic' 카테고리의 다른 글
What do the three dots (…) mean in JavaScript?: (...) = deepCopy, rest parameters (0) | 2021.02.26 |
---|---|
자바스크립트에서 물음표? 의 활용 (0) | 2020.05.25 |
javascript error문법 (1) | 2020.03.04 |
Arrow function사용법, 주의사항 (0) | 2020.02.13 |
함수형 프로그래밍이란 무엇인가? (1) | 2020.02.03 |