๐ฆ ์๋ฐ์คํฌ๋ฆฝํธ ๋น๋๊ธฐ ์ฒ๋ฆฌ ์์ ์ ๋ณต: Callback → Promise → async/await
์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ๋ฐฐ์ฐ๋ค ๋ณด๋ฉด ๊ผญ ํ ๋ฒ์ ๋ถ๋ชํ๋ ๊ฐ๋
์ด ์์ต๋๋ค.
๋ฐ๋ก ๋น๋๊ธฐ ์ฒ๋ฆฌ. ๊ทธ๋ฆฌ๊ณ ๊ทธ ํต์ฌ์ ์ฝ๋ฐฑ(callback), ํ๋ผ๋ฏธ์ค(Promise), async/await์
๋๋ค.
์ด ๊ธ์์๋ ๋น๋๊ธฐ ์ฒ๋ฆฌ ๋ฐฉ์์ด ์ด๋ป๊ฒ ๋ฐ์ ํด์๋์ง,
์ ์ฝ๋ฐฑ๋ง์ผ๋ก๋ ๋ถ์กฑํ๋์ง, ๊ทธ๋ฆฌ๊ณ async/await์ด ์ ๊น๋ํ์ง ๋จ๊ณ๋ณ๋ก ์ ๋ฆฌํด๋ณด๊ฒ ์ต๋๋ค.
โณ ๋น๋๊ธฐ ์ฒ๋ฆฌ๊ฐ ํ์ํ ์ด์
์๋ฐ์คํฌ๋ฆฝํธ๋ ๋จ์ผ ์ค๋ ๋ ๊ธฐ๋ฐ ์ธ์ด์์.
๊ทธ๋์ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ๋ ์์
(์: ์๋ฒ ์์ฒญ, ํ์ผ ์ฝ๊ธฐ ๋ฑ)์ ๊ทธ๋๋ก ์คํํ๋ฉด ์ ์ฒด๊ฐ ๋ฉ์ถฐ๋ฒ๋ ค์.
์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ๋ธ๋ผ์ฐ์ ๋ Node.js๋ ์ด๋ฐ ์์
์ ๋น๋๊ธฐ(Asynchronous)๋ก ์ฒ๋ฆฌํฉ๋๋ค.
์ฆ, “๋์ค์ ๊ฒฐ๊ณผ๊ฐ ์ค๋ฉด ์๋ ค์ค!” ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํ๊ฒ ๋ผ์.
โ 1. ์ฝ๋ฐฑ ํจ์ (Callback)
๐ ๊ฐ๋
์ฝ๋ฐฑ ํจ์๋ ๋ง ๊ทธ๋๋ก,
"์ด๋ค ๋ค๋ฅธ ํจ์์ ์ธ์๋ก ์ ๋ฌ๋์ด, ๋์ค์ ์คํ๋๋ ํจ์"
์ฆ, "ํน์ ์์ ๋๋๋ฉด ์ด ํจ์ ์คํํด์ค!" ํ๊ณ ๋๊ฒจ์ฃผ๋ ๋ฐฉ์์ ๋๋ค.
๐งช ์ฝ๋ฐฑ ํจ์ ์์
function doSomething(callback) {
console.log("์ผ์ ์์ํฉ๋๋ค...");
callback(); // ์ฌ๊ธฐ์ ์ ๋ฌ๋ ํจ์ ํธ์ถ
}
function finish() {
console.log("์ผ์ด ๋๋ฌ์ด์!");
}
doSomething(finish);
์ถ๋ ฅ ๊ฒฐ๊ณผ:
์ผ์ ์์ํฉ๋๋ค...
์ผ์ด ๋๋ฌ์ด์!
- finish() ํจ์๋ doSomething()์ ์ธ์(=callback)๋ก ์ ๋ฌ๋จ
- ์ค์ ์คํ์ doSomething() ์์์ callback()์ผ๋ก ์คํ๋จ
๐ง ์ฝ๋ฐฑ ํจ์๋ ์ธ์ ์ฐ์ด๋์?
์ด์ ํฌ์คํ ์๋ ์์ฑํ๋ฏ์ด, ์ฝ๋ฐฑํจ์๋ ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ์ ์ฌ์ฉ๋ฉ๋๋ค.
โ
1. ๋น๋๊ธฐ ์ฒ๋ฆฌ(setTimeout, setInterval, fetch(์๋ฒ ์๋ต) ๋ฑ)
→ ๋์ค์ ์ด๋ค ์ผ์ด ์ผ์ด๋๋ฉด ์คํํ๋ ๋ํ์ ์ธ ์
โ
2. ์ด๋ฒคํธ ํธ๋ค๋ง
→ ์ฌ์ฉ์์ ํ๋(ํด๋ฆญ, ์
๋ ฅ ๋ฑ)์ด ์ผ์ด๋ ๊ทธ ์์ ์๋ง ์คํ๋๋ ํจ์
โ
3. ๋ฐฐ์ด ๊ณ ์ฐจ ํจ์ (map, forEach, filter ๋ฑ)
→ ๊ฐ ๋ฉ์๋๋ ๋ฐฐ์ด ์์๋ง๋ค ์ฝ๋ฐฑ ํจ์๋ฅผ ํธ์ถํด์ ์ํ๋ ์์
์ ํ๊ฒ ๋ฉ๋๋ค.
โ ๏ธ ํ๊ณ – ์ฝ๋ฐฑ ์ง์ฅ (Callback Hell) ๋ฐ์
login(user, (userInfo) => {
getProfile(userInfo, (profile) => {
getPosts(profile, (posts) => {
render(posts);
});
});
});
- ์ฝ๋ฐฑ ์์ ์ฝ๋ฐฑ์ด ๊ณ์ ์ค์ฒฉ → ๊ฐ๋ ์ฑ ↓, ์๋ฌ ์ฒ๋ฆฌ ์ด๋ ค์
- ๊ทธ๋์ ๋ฑ์ฅํ ๊ฒ์ด Promise์ ๋๋ค.
์ด๊ฑธ ์ฝ๋ฐฑ ์ง์ฅ ์ด๋ผ๊ณ ํฉ๋๋ค.
๊ทธ๋์ ์ด๋ฅผ ๋ณด์ํ๊ณ ์ ๋์จ๊ฒ ๋ฐ๋ก Promise, async/await ์
๋๋ค!
๐ ์ฝ๋ฐฑ vs ์ผ๋ฐ ํจ์ ์ฐจ์ด
ํญ๋ชฉ | ์ผ๋ฐ ํจ์ | ์ฝ๋ฐฑ ํจ์ |
์ ์ ์์น | ๋ ๋ฆฝ์ ์ผ๋ก ์ ์๋จ | ๋ค๋ฅธ ํจ์ ์์ ์ธ์๋ก ์ ๋ฌ๋จ |
์คํ ์์ | ํจ์๊ฐ ํธ์ถ๋ ๋ | ๋ค๋ฅธ ํจ์๊ฐ ์คํ ์ค์ผ ๋ "ํธ์ถ๋จ" |
์ฉ๋ | ์ผ๋ฐ ์ฐ์ฐ, ๋ก์ง ์ํ | ๋น๋๊ธฐ ์ฒ๋ฆฌ, ์กฐ๊ฑด๋ถ ์คํ ๋ฑ |
๐ Bonus: ์ฝ๋ฐฑ์ด ๊ผญ ๋น๋๊ธฐ์ผ ํ์๋ ์๋ค!
function executeImmediately(callback) {
callback(); // ์ฆ์ ์คํ
}
executeImmediately(() => {
console.log("๋ฐ๋ก ์คํ๋๋ ์ฝ๋ฐฑ!");
});
- ์ฝ๋ฐฑ ํจ์๋ ๋จ์ํ "ํจ์๋ฅผ ์ ๋ฌ๋ฐ์๋ค๊ฐ ๋์ค์ ์คํํ๋ ๋ฐฉ์" ์ ๋๋ค.
- ๋ฐ๋ผ์ ๊ผญ ๋น๋๊ธฐ์ผ ํ์๋ ์์ต๋๋ค.
โ ์ ๋ฆฌ
๊ตฌ๋ถ | ์ฝ๋ฐฑ ํจ์ |
์ ์ | ๋ค๋ฅธ ํจ์์ ์ ๋ฌ๋์ด ๋์ค์ ํธ์ถ๋๋ ํจ์ |
์ฉ๋ | ๋น๋๊ธฐ ์์ ์ฒ๋ฆฌ, ์ด๋ฒคํธ ๋ฐ์, ๋ฐฐ์ด ์ํ ๋ฑ |
์ฅ์ | ์ ์ฐํ ํจ์ ์คํ, ์กฐ๊ฑด๋ถ ํ๋ฆ ์ ์ด |
๋จ์ | ์ฝ๋ฐฑ ์ง์ฅ ๋ฐ์ ๊ฐ๋ฅ, ์๋ฌ ์ฒ๋ฆฌ ์ด๋ ค์ |
๋ํ ์์ | setTimeout, fetch, addEventListener, map, forEach ๋ฑ |
โ 2. Promise
๐ ๊ฐ๋
Promise๋ ๋น๋๊ธฐ ์์ ์ ์ฑ๊ณต/์คํจ ๊ฒฐ๊ณผ๋ฅผ ๋ด๋ “์ฝ์ ๊ฐ์ฒด”์์.
์ฌ์ฉ๋ฒ
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('์ฑ๊ณต!');
// ํน์ reject('์๋ฌ ๋ฐ์!');
}, 1000);
});
๐งช ์ฌ์ฉ ์์
function fetchData() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('๋ฐ์ดํฐ ๋์ฐฉ!');
}, 1000);
});
}
fetchData()
.then((result) => console.log(result)) // ์ฑ๊ณต
.catch((err) => console.error(err)); // ์คํจ
โ ์ฅ์
- ์ค์ฒฉ ์์ด .then()์ผ๋ก ์ฒด์ด๋ ๊ฐ๋ฅ
- .catch()๋ก ์๋ฌ ์ฒ๋ฆฌ ๋ถ๋ฆฌ ๊ฐ๋ฅ
โ ๏ธ ๋จ์
- .then().then().then() ํํ๋ ์ฌ์ ํ ๋ณด๊ธฐ ๋ถํธํ ์ ์์
→ ๊ทธ๋์ ๋ฑ์ฅํ ๊ฒ์ด async/await
โ 3. async / await
๐ ๊ฐ๋
async ํค์๋๋ฅผ ํจ์์ ๋ถ์ด๋ฉด, ๊ทธ ํจ์๋ Promise๋ฅผ ๋ฐํํ๋ ํจ์๊ฐ ๋ฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๊ทธ ์์์ await์ ์ฐ๋ฉด, ๋น๋๊ธฐ ๊ฒฐ๊ณผ๋ฅผ ๋ง์น ๋๊ธฐ์ฒ๋ผ ๊ธฐ๋ค๋ฆด ์ ์์ต๋๋ค.
๐งช ์ฌ์ฉ ์์
function fetchData() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('๋ฐ์ดํฐ ๋์ฐฉ!');
}, 1000);
});
}
async function getData() {
try {
const result = await fetchData(); // ๋น๋๊ธฐ ์์
๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆผ
console.log(result);
} catch (err) {
console.error(err);
}
}
getData();
โ ์ฅ์
- ์ฝ๋๊ฐ ๊น๋ํ๊ณ ๊ฐ๋ ์ฑ ์ข์
- ๋ง์น ๋๊ธฐ ์ฝ๋์ฒ๋ผ ํ๋ฆ์ด ์์ฐ์ค๋ฝ๊ฒ ๋ณด์
- try-catch๋ก ์๋ฌ ์ฒ๋ฆฌ๋ ํธํจ
๐ง ์ ๋ฆฌ: ์ธ ๊ฐ์ง ๋ฐฉ์ ๋น๊ต
๊ตฌ๋ถ | ์ฝ๋ฐฑ | Promise | async/await |
๋์ ์๊ธฐ | ๊ฐ์ฅ ๊ธฐ๋ณธ | ES6 | ES2017 (ES8) |
๊ฐ๋ ์ฑ | โ ์ฝ๋ฐฑ ์ง์ฅ ๋ฐ์ | โ ๊ฐ์ ๋จ | โ ์ต๊ณ |
์๋ฌ ์ฒ๋ฆฌ | ์ด๋ ต๊ณ ๋ณต์ก | .catch()๋ก ๋ถ๋ฆฌ ๊ฐ๋ฅ | try/catch ์ฌ์ฉ |
๋๊ธฐ ์ฝ๋์ฒ๋ผ ๋ณด์ด๋์? | โ | โ | โ |
๋ํ ์ฌ์ฉ์ฒ | ์ด๋ฒคํธ, setTimeout | fetch, axios | ๋ชจ๋ ๋น๋๊ธฐ ํจ์ |
๐ ์ฝ๋ฐฑ์์ ์์ํด async/await๊น์ง: ์๋ฐ์คํฌ๋ฆฝํธ ๋น๋๊ธฐ ์ฒ๋ฆฌ ๋ฆฌํฉํฐ๋ง ํด๋ณด๊ธฐ
โ 1. ์ฝ๋ฐฑ(callback) ๋ฐฉ์
function login(user, callback) {
setTimeout(() => {
console.log('โ
๋ก๊ทธ์ธ ์๋ฃ');
callback({ id: 1, name: user });
}, 1000);
}
function getUserInfo(user, callback) {
setTimeout(() => {
console.log('๐ค ์ ์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ ์๋ฃ');
callback({ ...user, age: 25 });
}, 1000);
}
function getPosts(userInfo, callback) {
setTimeout(() => {
console.log('๐ ๊ฒ์๊ธ ๊ฐ์ ธ์ค๊ธฐ ์๋ฃ');
callback([`๊ฒ์๊ธ 1 by ${userInfo.name}`, `๊ฒ์๊ธ 2 by ${userInfo.name}`]);
}, 1000);
}
// ์ฝ๋ฐฑ ์ง์ฅ ์์
login('๋ค์', (user) => {
getUserInfo(user, (userInfo) => {
getPosts(userInfo, (posts) => {
console.log('๐ฆ ์ต์ข
๊ฒฐ๊ณผ:', posts);
});
});
});
โ ๋ฌธ์ ์
- ์ค์ฒฉ์ด ๊น์ด์ ธ์ ๊ฐ๋ ์ฑ์ด ๋๋น ์ง๊ณ ,
- ํ๋ฆ ํ์ ์ด ์ด๋ ต๊ณ ,
- ์๋ฌ ์ฒ๋ฆฌ๊ฐ ๋งค์ฐ ๋ณต์กํจ
โ 2. Promise ๋ฐฉ์์ผ๋ก ๊ฐ์
function login(user) {
return new Promise((resolve) => {
setTimeout(() => {
console.log('โ
๋ก๊ทธ์ธ ์๋ฃ');
resolve({ id: 1, name: user });
}, 1000);
});
}
function getUserInfo(user) {
return new Promise((resolve) => {
setTimeout(() => {
console.log('๐ค ์ ์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ ์๋ฃ');
resolve({ ...user, age: 25 });
}, 1000);
});
}
function getPosts(userInfo) {
return new Promise((resolve) => {
setTimeout(() => {
console.log('๐ ๊ฒ์๊ธ ๊ฐ์ ธ์ค๊ธฐ ์๋ฃ');
resolve([`๊ฒ์๊ธ 1 by ${userInfo.name}`, `๊ฒ์๊ธ 2 by ${userInfo.name}`]);
}, 1000);
});
}
// then ์ฒด์ด๋
login('๋ค์')
.then(getUserInfo)
.then(getPosts)
.then((posts) => {
console.log('๐ฆ ์ต์ข
๊ฒฐ๊ณผ:', posts);
})
.catch((err) => {
console.error('์๋ฌ ๋ฐ์:', err);
});
๐งโ๏ธ ๊ฐ์ ์
- ์ค์ฒฉ ์์ด ์ง๊ด์ ์ธ ํ๋ฆ
- .catch()๋ก ์๋ฌ ์ฒ๋ฆฌ ๋ถ๋ฆฌ ๊ฐ๋ฅ
โ 3. async/await ๋ฐฉ์์ผ๋ก ๋ฆฌํฉํฐ๋ง
async function fetchUserPosts() {
try {
const user = await login('๋ค์');
const userInfo = await getUserInfo(user);
const posts = await getPosts(userInfo);
console.log('๐ฆ ์ต์ข
๊ฒฐ๊ณผ:', posts);
} catch (err) {
console.error('์๋ฌ ๋ฐ์:', err);
}
}
fetchUserPosts();
โ ์ฅ์
- ์ฝ๋๊ฐ ๋๊ธฐ ํ๋ฆ์ฒ๋ผ ์์ฐ์ค๋ฝ๊ณ ์ฝ๊ธฐ ์ฌ์
- try/catch๋ก ์๋ฌ ์ฒ๋ฆฌ๋ ๊ฐ๊ฒฐ
โจ ์ฝ๋ฐฑ → Promise → async/await
๋ฐฉ์ | ์ฝ๋ ๊ตฌ์กฐ | ์๋ฌ ์ฒ๋ฆฌ | ๊ฐ๋ ์ฑ | ์ ์ง ๋ณด์ |
์ฝ๋ฐฑ | ์ค์ฒฉ ๊ตฌ์กฐ (์ง์ฅ) | ๋ณต์ก | โ | โ |
Promise | ์ฒด์ด๋ | .catch() | โณ | โณ |
async/await | ๋๊ธฐ ํ๋ฆ์ฒ๋ผ | try/catch | โ | โ |
โจ ๋ง๋ฌด๋ฆฌ
๋น๋๊ธฐ ์ฝ๋๋ฅผ ์์ฑํ ๋ ๊ฐ์ฅ ์ค์ํ ๊ฑด ์ฝ๋์ ํ๋ฆ์ ์ฝ๊ธฐ ์ฝ๊ฒ ๋ง๋๋ ๊ฒ์
๋๋ค.
์ฝ๋ฐฑ์ ๊ฐ๋จํ ๋ก์ง์์๋ ์ ์ฉํ์ง๋ง, ์กฐ๊ธ๋ง ๋ณต์กํด์ง๋ฉด ๊ธ์ธ ์ง์ฅ์ ๋ณด์ฌ์ฃผ์ฃ .
์๋ฐ์คํฌ๋ฆฝํธ์์ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ ํ์์
๋๋ค.
์ฝ๋ฐฑ → Promise → async/await์ผ๋ก ์ ์ ๋ ์ฝ๊ธฐ ์ฝ๊ณ ์ ์ง๋ณด์ ์ข์ ์ฝ๋๋ก ๋ฐ์ ํด์์ด์.
์ง๊ธ๋ถํฐ๋ async/await์ด ํ์ค์ฒ๋ผ ์ฌ์ฉ๋์ง๋ง, ์ด ํ๋ฆ์ ์ดํดํ๋ ๊ฒ ์ง์ง ์ค๋ ฅ์ ๋ง๋ค์ด์ค๋๋ค.