์ด๋ฒ ํฌ์คํ ์์ promise, async await์ ์ฐจ์ด์ ์ ์์๋ณด์!
1. ์๋ฐ์คํฌ๋ฆฝํธ์์ ๋น๋๊ธฐ ์ฒ๋ฆฌ๊ฐ ํ์ํ ์ด์
- js๋ ๋๊ธฐ์ ์ธ ์ธ์ด์ด๋ ๋๊ธฐ์๊ฐ์ด ๊ธด ์์ (์๋ฒ์ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๋ ์์ )์ ํ๋ ๊ฒฝ์ฐ ๋น๋๊ธฐ ์์ ์ ํ๊ธฐ๋ ํ๋ค.
- ์๋๋ ๋น๋๊ธฐ ์ฒ๋ฆฌ๊ฐ ํ์ํ ๊ฐ๋จํ ์์์ด๋ค.
- getHotels()๋ ์๋ฒ์์ ํธํ ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ค๋ ํจ์์ด๋ค.
- ๊ทธ๋ฆฌ๊ณ ์ฐ๋ฆฌ๋ getHotels()์ ์๋ต๊ฐ์ ๋ฐ์ ์ถ๋ ฅํ๊ณ ์ถ๋ค.
function printHotels() {
const hotels = getHotels();
console.log(hotels);
}
์์ ๊ฐ์ด ์์ฑํ๋ฉด Hotels()์ ๊ฐ์ด ์ถ๋ ฅ๋ ๊น?
- ๋ต์ No
- ์? ์๋ฐ์คํฌ๋ฆฝํธ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋๊ธฐ์ ์ธ ์ธ์ด์ด์ง๋ง, ๋๊ธฐ์๊ฐ ๊ธด ์์ ์ ๊ฒฝ์ฐ ๋น๋๊ธฐ๋ก ์์ ํ๊ธฐ ๋๋ฌธ์ getHotels()๋ณด๋ค ์ฝ์ ์ถ๋ ฅ์ด ๋จผ์ ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ ์ฝ์์ฐฝ์๋ undefined๊ฐ ์ถ๋ ฅ๋๋ค.
function printHotels() {
const hotels = getHotels(); // ์ด๊ฒ๋ด๋ผ? ๋๊ธฐ ์๊ฐ์ด ๋๋ฌด ๊ธฐ๋ค?
console.log(hotels); // ๊ทธ๋ผ ํด๋น ์ถ๋ ฅ ์ฝ๋ ๋จผ์ ์คํํ์
}
printAnimals(); // undefined
- ๊ทธ๋ ๋ค๋ฉด getHotels()์ ์๋ต๊ฐ(response)๋ฅผ ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด ์ด๋ค ์กฐ์น๋ฅผ ์ทจํด์ค์ผ ํ ๊น?
- ๋ฐ๋ก ์ด ๋ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฐฉ์ promise, async await๋ฅผ ์ฌ์ฉํด ์ค๋ค. ๊ทธ๋ ๋ค๋ฉด ์ด๋ค์ ์ฐจ์ด์ ์?
์๋๋ ์๋ฐ์คํฌ๋ฆฝํธ์์ ๋น๋๊ธฐ ์ฒ๋ฆฌ๊ฐ ํ์ํ ๋ช ๊ฐ์ง ์์์ด๋ค.
1. ์๋ฒ๋ก๋ถํฐ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ (AJAX ์์ฒญ)
2. ํ์ผ ์ฝ๊ธฐ/์ฐ๊ธฐ
3. ํ์ด๋จธ ํจ์ ์ฌ์ฉ
4. Promise์ async/await ์ฌ์ฉ
1-1. ์๋ฒ๋ก๋ถํฐ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ (AJAX ์์ฒญ)
์น ์ ํ๋ฆฌ์ผ์ด์
์์ ์๋ฒ๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ์์
์ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆด ์ ์๋ค. ์ด ์์
์ ๋๊ธฐ๋ก ์ฒ๋ฆฌํ๋ฉด ๋ฐ์ดํฐ๊ฐ ๋์ฐฉํ ๋๊น์ง ๋ค๋ฅธ ๋ชจ๋ ์์
์ด ๋ธ๋ก๋๋ค.
[์๋ชป๋ ์์]
// ๋๊ธฐ์ ์ฒ๋ฆฌ ์์ (๋์ ์์)
function fetchDataSync() {
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.example.com/data", false); // false: ๋๊ธฐ์
xhr.send(null);
if (xhr.status === 200) {
console.log(xhr.responseText);
}
}
fetchDataSync();
console.log("์ด ๋ฉ์์ง๋ ๋ฐ์ดํฐ๊ฐ ๋ชจ๋ ๋ก๋๋ ํ์์ผ ์ถ๋ ฅ๋ฉ๋๋ค."); // ์ด ๋ฉ์์ง๋ ๋ฐ์ดํฐ๊ฐ ๋์ฐฉํ ํ์ ์ถ๋ ฅ๋จ
์ ์ฝ๋๋ฅผ ์๋์ฒ๋ผ ๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ฉด ๋ค๋ฅธ ์์
์ด ๋ธ๋ก๋์ง ์๋๋ค.
[์ข์ ์์]
// ๋น๋๊ธฐ์ ์ฒ๋ฆฌ ์์ (์ข์ ์์)
function fetchDataAsync() {
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.example.com/data", true); // true: ๋น๋๊ธฐ์
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText);
}
};
xhr.send(null);
}
fetchDataAsync();
console.log("์ด ๋ฉ์์ง๋ ๋ฐ์ดํฐ๊ฐ ๋ก๋๋๊ธฐ ์ ์ ์ถ๋ ฅ๋ ์ ์์ต๋๋ค."); // ์ด ๋ฉ์์ง๋ ์ฆ์ ์ถ๋ ฅ๋จ
1-2. ํ์ผ ์ฝ๊ธฐ/์ฐ๊ธฐ
ํ์ผ ์์คํ
์ ์ ๊ทผํ๋ ์์
์ ์ค๋ ๊ฑธ๋ฆด ์ ์๋ค. ์ด๋ฅผ ๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌํ์ง ์์ผ๋ฉด ํ์ผ ์ฝ๊ธฐ/์ฐ๊ธฐ ์์
์ด ์๋ฃ๋ ๋๊น์ง ์๋ฐ์คํฌ๋ฆฝํธ๊ฐ ๋ฉ์ถ๋ค.
[์๋ชป๋ ์์]
const fs = require('fs');
// ๋๊ธฐ์ ํ์ผ ์ฝ๊ธฐ (๋์ ์์)
function readFileSync() {
const data = fs.readFileSync('/path/to/file', 'utf8');
console.log(data);
}
readFileSync();
console.log("์ด ๋ฉ์์ง๋ ํ์ผ์ด ๋ชจ๋ ์ฝํ ํ์์ผ ์ถ๋ ฅ๋ฉ๋๋ค."); // ์ด ๋ฉ์์ง๋ ํ์ผ์ด ์ฝํ ํ์ ์ถ๋ ฅ๋จ
[์ข์ ์์]
// ๋น๋๊ธฐ์ ํ์ผ ์ฝ๊ธฐ (์ข์ ์์)
function readFileAsync() {
fs.readFile('/path/to/file', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
}
readFileAsync();
console.log("์ด ๋ฉ์์ง๋ ํ์ผ์ด ์ฝํ๊ธฐ ์ ์ ์ถ๋ ฅ๋ ์ ์์ต๋๋ค."); // ์ด ๋ฉ์์ง๋ ์ฆ์ ์ถ๋ ฅ๋จ
1-3. ํ์ด๋จธ ํจ์ ์ฌ์ฉ
ํ์ด๋จธ ํจ์(setTimeout, setInterval)๋ ์ผ์ ์๊ฐ์ด ์ง๋ ํ์ ํน์ ์์ ์ ์ํํด์ผ ํ ๋ ์ ์ฉํ๋ค. (๋น๋๊ธฐ์ ์๋)
// setTimeout์ ์ฌ์ฉํ ๋น๋๊ธฐ ์ฒ๋ฆฌ
console.log("์ด ๋ฉ์์ง๋ ์ฆ์ ์ถ๋ ฅ๋ฉ๋๋ค.");
setTimeout(() => {
console.log("์ด ๋ฉ์์ง๋ 2์ด ํ์ ์ถ๋ ฅ๋ฉ๋๋ค.");
}, 2000);
console.log("์ด ๋ฉ์์ง๋ ์ฆ์ ์ถ๋ ฅ๋ฉ๋๋ค."); // ์ด ๋ฉ์์ง๋ setTimeout ์ฝ๋ฐฑ ์ด์ ์ ์ถ๋ ฅ๋จ
1-4. Promise์ async/await ์ฌ์ฉ
๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ํด Promise์ async/await๋ฅผ ์ฌ์ฉํ๋ฉด ์ฝ๋ ๊ฐ๋ ์ฑ์ด ํฅ์๋จ.
// Promise๋ฅผ ์ฌ์ฉํ ๋น๋๊ธฐ ์ฒ๋ฆฌ
function fetchData() {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.example.com/data", true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
resolve(xhr.responseText);
} else if (xhr.readyState === 4) {
reject("Error fetching data");
}
};
xhr.send(null);
});
}
fetchData()
.then(data => {
console.log(data);
})
.catch(error => {
console.error(error);
});
// async/await๋ฅผ ์ฌ์ฉํ ๋น๋๊ธฐ ์ฒ๋ฆฌ
async function fetchDataAsync() {
try {
const data = await fetchData();
console.log(data);
} catch (error) {
console.error(error);
}
}
fetchDataAsync();
console.log("์ด ๋ฉ์์ง๋ fetchDataAsync ํธ์ถ ํ์ ์ฆ์ ์ถ๋ ฅ๋ฉ๋๋ค."); // ์ด ๋ฉ์์ง๋ ์ฆ์ ์ถ๋ ฅ๋จ
2. promise vs async await
2-1. async๋ฅผ ์ฌ์ฉํ๋ฉด ์ฝ๋๊ฐ ๊ฐ๊ฒฐํ๋ค.
- ์์ ์์ getHotels()๋ฅผ ํธ์ถํ์ฌ ์๋ต๊ฐ์ ๋ฐ๊ณ , ์ด ์๋ต๊ฐ์ ์ถ๋ ฅํ๊ณ ์ ํ๋ค.
- promise์ then๋ฐฉ์์ ์ฝ๋๋ ์๋์ ๊ฐ๋ค.
function print Hotels() {
getHotels().then((data) => {
console.log(data);
})
}
- ์ด ์ฝ๋๋ฅผ async await๋ก ๋ฐ๊พธ๊ณ ์ถ๋ค. => ํจ์์ async ํค์๋๋ฅผ ์ ๊ณ , ๋น๋๊ธฐ ๋์์ await๋ฅผ ์ถ๊ฐ
- ๋น๋๊ธฐ ๋์ ํจ์์ await๋ฅผ ์ถ๊ฐ๋ ๊ฒ => 'ํด๋น ํจ์์ ์ฒ๋ฆฌ๋ฅผ ๊ธฐ๋ค๋ ค!'
- ๊ทธ๋ฆฌ๊ณ await ํจ์ ์๋์ ํด๋น ํจ์์ ์๋ต๊ฐ์ ์ฌ์ฉํ๋ ๊ตฌ๋ฌธ์ ์ถ๊ฐํด์ฃผ์.
async function printHotels() {
const hotels = await getHotels(); // ํด๋น ํจ์์ฒ๋ฆฌ ๋๋ ๋๊น์ง ๊ธฐ๋ค๋ ค!
console.log(hotels) // ์๋ต๊ฐ ์ถ๋ ฅ๋จ
}
์ฌ๊ธฐ๊น์ง๋ ์ฝ๋๊ฐ ๋ณ๋ก ๊ธธ์ง ์์์ promise them๊ณผ async await์ ์ฐจ์ด๊ฐ ๊ฑฐ์ ๋๊ปด์ง์ง ์๋๋ค.
๊ทธ๋ ๋ค๋ฉด ์ฝ๋๋ฅผ ๋๋ ค ๋ณด์.
[promise then ๋ฐฉ์]
function printHotels() {
return getHotels()
.then(data => {
if (data.property) {
return sampleFunc1(data)
.then(anotherData => {
console.log(anotherData)
})
}else {
console.log(data)
}
})
}
=> ์ ์ฝ๋๋ ๋ผ์ธ ์๋ ๋ง๊ณ ๋ค์ฌ์ฐ๊ธฐ๊ฐ ๋ณต์กํจ
[async await ๋ฐฉ์(๊ถ์ฅ) ]
async function printHotels() {
const hotels = await getHotels();
if (hotels.property) {
const sampleData = await sampleFunc1(hotels);
console.log(sampleData);
}else {
console.log(hotels);
}
}
=> then ๋ฐฉ์๊ณผ ๋น๊ตํ์ ๋ ๋ค์ฌ์ฐ๊ธฐ๋ ๊ฐ๋จํ๊ณ ์ฝ๋๊ฐ ๊ฐ๊ฒฐํจ.
=> ์๋ต๊ฐ์ด ๋ณ์์ ๋ด๊ธฐ๊ธฐ ๋๋ฌธ์ ์ง๊ด์ ์
2-2. async๋ฅผ ์ฌ์ฉํ๋ฉด ์๋ฌ ํธ๋ค๋ง์ด ์ฝ๋ค.
- ์๋ฒ์ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๋ ์์ ์ ํ๋ค๋ณด๋ฉด, ์๋ฌ๊ฐ ๋ฐ์ํ ๊ฐ๋ฅ์ฑ์ ์ผ๋์ ๋๊ณ ์ฝ๋๋ฅผ ์ง์ผ ํ๋ค.
- ์๋ฌ ํธ๋ค๋ง์ ์ธ ์ธก๋ฉด์์ async await๊ฐ ์ข ๋ ์ ๋ฆฌํ๋ค.
- printHotels()์์ ์๋ฌ๊ฐ ๋ฐ์ํ ๊ฒ์ด ์๋๊ณ JSON.parse์์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค๊ณ ๊ฐ์ ํจ.
- ์ด ๊ฒฝ์ฐ, then์ ์ฌ์ฉํ๋ฉด catch๋ฌธ์ ์ถ๊ฐํด์ฃผ์ด์ผ ํ๋ค.
- ์ฆ catch๋ฌธ์ด ์ค๋ณต๋๋ค.
function printHotels() {
try {
getHotels()
.then((response) => {
const data = JSON.parse(response); // ์๋ฌ ๋ฐ์ํ ๋ถ๋ถ
console.log(data);
})
.catch((err)=> { // ์ถ๊ฐ์ ์ธ ์๋ฌ
console.log(err)
})
}
catch(err) {
console.log(err)
}
}
async function printHotels() {
try {
const data = await JSON.parse((getHotels())
console.log(data);
}
catch(err) {
console.log(err)
}
}
- ๋ฐ๋ฉด async await๋ฅผ ํด ์ฃผ๋ฉด catch๋ฌธ ํ๋๋ก try ๋ด๋ถ์์ ๋ฐ์ํ๋ ๋ชจ๋ ์๋ฌ์ ์ ๊ทผ ๊ฐ๋ฅํจ.
2-3. async๋ฅผ ์ฌ์ฉํ๋ฉด ์ด๋ค ์ง์ ์์ ์๋ฌ๊ฐ ๋ฐ์ํ๋์ง ์ฝ๊ฒ ์ฐพ์ ์ ์๋ค.
[async await] : ์ข์ ์์
async function fetchData() {
const response = await fetch("https://api.example.com/data");
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
}
async function processData() {
try {
const data = await fetchData();
console.log(data);
} catch (error) {
console.error("Error fetching data:", error.message);
}
}
processData();
console.log("This message is logged immediately after processData is called.");
- fetchData ํจ์๋ fetch๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์จ๋ค.
- await ํค์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋น๋๊ธฐ ์์ ์ด ์๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฐ๋ค.
- ์๋ต์ด ์ฑ๊ณต์ ์ด์ง ์์ ๊ฒฝ์ฐ(response.ok๊ฐ false), ์๋ฌ๋ฅผ ๋ฐ์์ํด
- processData ํจ์๋ fetchData๋ฅผ ํธ์ถํ๊ณ , try-catch ๋ธ๋ก์ ์ฌ์ฉํ์ฌ ์๋ฌ ์ฒ๋ฆฌ๋ฅผ ํด ์ค๋ค.
- ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด, catch ๋ธ๋ก์์ ์๋ฌ ๋ฉ์์ง๋ฅผ ์ถ๋ ฅ
์์์ ๋ณธ ๊ฒ์ฒ๋ผ async await๋ฅผ ์จ ์ฃผ๋ฉด ์ฝ๋๊ฐ ๋๊ธฐ์ ์ผ๋ก ์์ฑ๋ ๊ฒ์ฒ๋ผ ๋ณด์ด๊ธฐ ๋๋ฌธ์, ์๋ฌ๊ฐ ๋ฐ์ํ์ ๋ ์ด๋ ๋ถ๋ถ์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋์ง ์ฝ๊ฒ ์ถ์ ๊ฐ๋ฅํ๋ค. ์๋ฅผ ๋ค์ด, fetchData ํจ์ ๋ด์์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด processData์ catch ๋ธ๋ก์์ ์ด๋ฅผ ์ก์ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ด๋ค.
[Promise ์ฌ์ฉ ์์ ] : ๋์ ์์
- ํ๋ก๋ฏธ์ค๊ฐ ์ฐ์์ ์ผ๋ก ํธ์ถ๋๋ฉด ์ด๋ค then ์ง์ ์์ ์๋ฌ๊ฐ ๋ฐ์ํ๋์ง ์ฐพ๊ธฐ๊ฐ ์ด๋ ต๋ค.
function fetchData() {
return fetch("https://api.example.com/data")
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
});
}
function processData() {
fetchData()
.then(data => {
console.log(data);
})
.catch(error => {
console.error("Error fetching data:", error.message);
});
}
processData();
console.log("This message is logged immediately after processData is called.");
์ด ์์ ์์ Promise ์ฒด์ธ์ then ๋ธ๋ก์ด ์ฌ๋ฌ ๊ฐ์ผ ๊ฒฝ์ฐ ์๋ฌ๊ฐ ๋ฐ์ํ ์์น๋ฅผ ๋ช
ํํ ํ์
ํ๊ธฐ ์ด๋ ค์ธ ์ ์๋ค.
๋ ์ฌ๋ฌ ๊ฐ์ ์ค์ฒฉ๋ ๋น๋๊ธฐ ์์
์ด ์์ ๊ฒฝ์ฐ, ์ฝ๋ฐฑ ์ง์ฅ(callback hell)์ด ๋ฐ์ํ์ฌ ์ฝ๋ ๊ฐ๋
์ฑ์ด ๋จ์ด์ง๋ค.
์ฆ, async๋ฅผ ์จ ์ฃผ๋ฉด ๋๋ฒ๊ทธ๋ฅผ ํ ๋ then๊ณผ ๋ฌ๋ฆฌ ์ ํํ ์์น๋ฅผ ์ง์ ํ ์ ์๋ ์ฅ์ ์ด ์๋ค.