JavaScript ๋น๋๊ธฐ ์ฒ๋ฆฌ
์๋ฐ์คํฌ๋ฆฝํธ ๋น๋๊ธฐ ์ฒ๋ฆฌ
์๋ฐ์คํฌ๋ฆฝํธ๋ ์ฑ๊ธ ์ค๋ ๋ ๊ธฐ๋ฐ์ ์ธ์ด๋ก, ํ ๋ฒ์ ํ๋์ ์์ ๋ง ์ฒ๋ฆฌํ ์ ์๋ค. ํ์ง๋ง ๋น๋๊ธฐ ์ฒ๋ฆฌ ๋ฐฉ์์ ํตํด ๋ณ๋ ฌ ์์ ์ด ๊ฐ๋ฅํด ๋ณด์ด๊ฒ ๋ง๋ค ์ ์๋ค. ์ฃผ๋ก I/O ์์ (๋คํธ์ํฌ ์์ฒญ, ํ์ผ ์ฝ๊ธฐ ๋ฑ)์ด๋ ํ์ด๋จธ์ ๊ฐ์ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ๋ ์์ ์์ ์ฌ์ฉ๋๋ค.
- ๋๊ธฐ์ (Synchronous) ์ฒ๋ฆฌ : ํ๋์ ์์ ์ด ์๋ฃ๋ ๋๊น์ง ๋ค์ ์์ ์ ์์ํ์ง ์๋ ๋ฐฉ์. ์ฆ ์์ ์ด ์์ฐจ์ ์ผ๋ก ์งํ๋๋ค.
console.log("Start");
for (let i = 0; i < 100000000; i++) {
// ์๊ฐ์ด ์ค๋๊ฑธ๋ฆฌ๋ ์์
}
console.log("End");
์ ์ฝ๋๋ `for`๋ฃจํ๊ฐ ๋๋ ๋ ๊น์ง ๋ค๋ฅธ ์์ ์ด ์คํ๋์ง ์๊ณ ๊ธฐ๋ค๋ฆฐ๋ค. ์ฆ, "End"๊ฐ ์ถ๋ ฅ๋๊ธฐ ์ ๊น์ง ๋ชจ๋ ์์ ์ด ๋ฉ์ถ ์ํ๋ก ๋๊ธฐํ๊ฒ ๋๋ค. CPU๋ฅผ ๋ ์ ํ๊ธฐ ๋๋ฌธ์, ๊ธด ์์ ์ด ์์ผ๋ฉด ํ์ด์ง๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ฉ์ถ ๊ฒ ์ฒ๋ผ ๋๊ปด์ง ์ ์๋ค.
- ๋น๋๊ธฐ์ (Asynchronous) ์ฒ๋ฆฌ: ์์ ์ ์์ํ ํ ํด๋น ์์ ์ด ๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ , ๋ค์ ์์ ์ ๋จผ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ์์ด๋ค. ์์ ์ด ์๋ฃ๋๋ฉด CallBack ํจ์๋ Promise ๋ฑ์ ์ฌ์ฉํด ๊ฒฐ๊ณผ๋ฅผ ์ฒ๋ฆฌํ๋ค.
console.log("Start");
setTimeout(() => {
console.log("This runs after 2 seconds");
}, 2000);
console.log("End");
์ ์ฝ๋์์ `setTimeout` ํจ์๋ 2์ด ํ์ ์คํ๋์ง๋ง, "End"๋ ๋ฐ๋ก ์ถ๋ ฅ๋๋ค.
์ฆ, ๋น๋๊ธฐ ์์ ์ธ `setTimeout`์ด ์ฒ๋ฆฌ๋๋ ๋์ ๋ค๋ฅธ ์์ ๋ค์ด ๊ณ์ํด์ ์คํ๋๋ค.
Callback: ํจ์ ํ๋ผ๋ฏธํฐ + ์คํ๊ถ ์ด์
Callback ≠ Asynchronous
- ํจ์๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ๋๊ธฐ๋ ๊ฒ
- ํ๋ผ๋ฏธํฐ ๋ฐ์ ํจ์์๊ฒ ์คํ๊ถ์ ๋๊ธฐ๋ ๊ฒ
Callback์ ํจ์๊ฐ ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌ๋๊ณ , ๊ทธ ์คํ๊ถ์ด ํด๋น ํจ์๋ก ์ด์๋๋ ๊ตฌ์กฐ์ด๋ค. ๋น๋๊ธฐ ์์ ์ด ๋๋ ํ ์คํ๋๋ ํจ์๋ก ๋ง์ด ์ฌ์ฉ๋๋ค.
function callback(param1, param2) {
console.log(param1 + " and " + param2);
}
function caller(callback) {
setTimeout(() => {
callback(arguments[1], arguments[2]);
}, 2000);
}
caller(callback, "Hello, "GoodBye");
function summation(param1, param2) {
console.log(`${param1} + ${param2}`)
}
// summation('Hello', 'World')
function summation_caller(callback/* callee */, param1, param2) {
// callback(param1, param2)
setTimeout(
/* ๋ฌด์์ ํธ์ถํ ๋์? */ () => callback(param1, param2),
/* ๋ช์ด๋ค ํธ์ถํ ๋์? */ 1000
);
}
summation_caller(summation, 'Hello', 'World')
- Callback ์์ฒด๋ก๋ ๋น๋๊ธฐ ํจ์์ ์ง์ ์ ์ธ ๊ด๊ณ๋ ์์ผ๋ ๋น๋๊ธฐ ๋ก์ง์ด ๋๋๋ฉด ๊ทธ ๋น๋๊ธฐ ๋ก์ง์ ๊ฒฐ๊ณผ๊ฐ์ ํตํด Callback์ ์คํํ๋ค.→ ๋น๋๊ธฐ ํจ์์๊ฒ ์คํ๊ถ์ ๋๊ธฐ๊ธฐ ์ํด Callback์ ๋ง์ด ์ฌ์ฉํ ๋ฟ์ด๋ค.
- ํจ์๊ฐ ๋๋ ํ ์คํํ ํจ์๋ฅผ ์ธ์๋ก ์ ๋ฌํ์ฌ ์ฒ๋ฆฌํ๋ค. ํ์ง๋ง ์ฝ๋ฐฑ ํจ์๋ ์ค์ฒฉ๋ ์๋ก ์ฝ๋๊ฐ ๋ณต์กํด์ง๋ฉฐ ์ฝ๋ฐฑ ์ง์ฅ(Callback Hell)์ ์ผ๊ธฐํ ์์๋ค.
Callback Hell(์ฝ๋ฐฑ ์ง์ฅ)
๋น๋๊ธฐ ์์ ์ ์ํํ ๋, ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ฌ๋ฌ ๋จ๊ณ์ Callback์ ์ฒ๋ฆฌํด์ผ ํ ๋ Callback Hell์ด ๋ฐ์ํ๋ค.
Callbacl Hell ์์ ์ฝ๋
const egg = '๐ฅ';
eggToChick(
/* 1๋จ๊ณ ๋ฌ๊ฑ */egg,
/* 2๋จ๊ณ ํจ์ */(chick) =>
chickToHen(
/* 2๋จ๊ณ ์์ฝ */ chick,
/* 3๋จ๊ณ ํจ์*/(hen) =>
henToEgg(
/* 3๋จ๊ณ ๊ผฌ๊ผฌ */ hen,
/* 4๋จ๊ณ ํจ์ */ (egg) => eggToFried(egg)
)
)
)
function eggToChick(egg, handleChick) {
const chick = "๐ฅ"
console.log("egg to chick : ", egg, "", chick)
handleChick(chick)
}
function chickToHen(chick, handleHen) {
const hen = "๐"
console.log("chick to hen : ", chick, " → ", hen)
handleHen(hen)
}
function henToEgg(hen, handleEgg) {
const egg = "๐ฅ"
console.log("hen to egg : ", hen, " → ", egg)
handleEgg(egg)
}
function eggToFried(egg) {
const fried = "๐ณ"
console.log("egg to fried : ", egg, " → ", fried)
}
์คํ๊ฒฐ๊ณผ
egg to chick : ๐ฅ ๐ฅ
chick to hen : ๐ฅ → ๐
hen to egg : ๐ → ๐ฅ
egg to fried : ๐ฅ → ๐ณ
์ฝ๋ฐฑ์ด ์ค์ฒฉ๋์ด ์ฝ๋๊ฐ ๋ณต์กํด์ง๋ ํ์์ด๋ค. ์ด๋ฐ ์ค์ฒฉ๋ ์ฝ๋๋ ์ฝ๊ธฐ ์ด๋ ต๊ณ ์ ์ง๋ณด์๊ฐ ํ๋ค๊ธฐ ๋๋ฌธ์ ์ถํ์ ๋์ค๋ Promise๋ฅผ ๋์ ํ๊ฒ ๋๋ค.
Promise
Callback + Asynchronous = Promise
Promise๋ ๋น๋๊ธฐ ์์ ์ ๋ค๋ฃจ๊ธฐ ์ํ ๊ฐ์ฒด์ด๋ค. ์ฝ๋ฐฑ ํฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ณ , ๋น๋๊ธฐ ์์ ์ ๊ฒฐ๊ณผ๋ฅผ ๋ ๊ตฌ์กฐํ ๋ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํ ์ ์๊ฒ ํด์ค๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก Promise๋ ๋น๋๊ธฐ ์์ ์ด ์๋ฃ๋์์ ๋, ์ฑ๊ณตํ๊ฑฐ๋ ์คํจํ ๊ฒฐ๊ณผ๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ ๋๊ฐ์ง ์ํ๋ก ๊ตฌ๋ถ๋๋ค.
- Asynchronous ๋น๋๊ธฐ ํจ์ (Executor) : Caller = Producer (ํ๋ผ๋ฏธํฐ ์ฃผ์ )
- Callback ๋น๋๊ธฐ ์ฒ๋ฆฌ ํ ์ํํ ํจ์ (Executee): Callee = Consumer(ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ์ ์ํ)
- Executor์๊ฒ ์์ ์ ์ ์ด๊ถ์ ๋๊ธด๋ค
- Promise๋ฅผ Producer-Consumer Pattern on Asynchronouse๋ผ๊ณ ํํํ๊ธฐ๋ ํ๋ค.
function caller(callee) {
var produced = producing();
callee(produced)
}
caller(function callee(produced) {
consuming(produced);
});
Promise์ ์ํ์ ๊ทธ์ ๋ฐ๋ฅธ ์ฝ๋ฐฑ
- Pending (๋๊ธฐ): ๋น๋๊ธฐ ์์ ์ด ์์ง ์๋ฃ๋์ง ์์ ์ํ.
- Fulfilled (์ฑ๊ณต): ๋น๋๊ธฐ ์์ ์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋ ์ํ. resolve() ํธ์ถ.
- Rejected (์คํจ): ๋น๋๊ธฐ ์์ ์ด ์คํจํ ์ํ. reject() ํธ์ถ
Promise ์ฝ๋ ์์:
- Callback ํํ(Pseudo ์ฝ๋)
- Resolve ์ฑ๊ณต ์ ์คํํ ์ฝ๋ฐฑ
- Reject ์คํจ ์ ์คํํ ์ฝ๋ฐฑ
์์ ์ฝ๋(1)
function producing() {
return { success: true, value: '์ฑ๊ณตํ์ต๋๋ค :)' }; // ์ฑ๊ณต ์ฌ๋ถ์ ๋ฐ๋ผ ์์ ๊ฐ๋ฅ
}
function producer(resolve, reject) {
var produced = producing();
if (produced.success) {
resolve(produced.value);
} else {
reject(produced.value);
}
}
producer(
/* ์ฑ๊ณต ์ฝ๋ฐฑ */
function resolve(fulfilled) {
console.log('์ฑ๊ณต๐ ' + fulfilled);
},
/* ์คํจ ์ฝ๋ฐฑ */
function reject(rejected) {
console.log('์คํจ๐ ' + rejected);
}
);
์์ ์ฝ๋(2)
function caller(resolve, reject) {
const produced = producing() // API ํธ์ถํด์ค, ์ด๋ฏธ์ง ๊ฐ์ ธ์์ค
if (succeeded) resolve(produced)
if (failed) reject(produced)
}
caller(
function resolve(produced) { consuming(produced) },
function reject(produced) { consuming(produced) },
)
- Promise๋ก ๋ณํ (Pseudo ์ฝ๋, ๊ธฐ๋ณธ ํจ์ ๋ฆฌํฐ๋ด)
์์ ์ฝ๋(1) // ์ค๋ฌด์์ ์ฌ์ฉํ๋ ํํ(์ค์ ์ฝ๋, ํ์ดํ ํจ์)
function fetchUserInformation(id) {
if ( id === 1 ) {
return { status: 200, user: { name: 'CheonSang', age: 10 } }
} else {
return { status: 500, user: undefined }
}
}
const id = 2
new Promise(
function producer(resolve, reject) {
const result = fetchUserInformation(id)
if (result.status === 200) { resolve(result.user) }
if (result.status === 500) { reject() }
}
)
.then((user) => console.log('์ฑ๊ณต :) - ' + JSON.stringify(user)))
.catch(( ) => console.log('์คํจ :( - ์ ์ ๊ฐ ... ์๋ต๋๋ค!'))
.finally(( ) => console.log(' - ๋ - '))
์์ ์ฝ๋(2)
new Promise(function caller(resolve, reject) {
const produced = producing();
if (succeeded) resolve(produced);
if (failed) reject(produced);
})
.then(function resolve(produced) { consuming(produced) })
.catch(function reject(produced) { consuming(produced) });
Promise์ ์ํ ๊ด๋ฆฌ
- Pending ์ํ: ๋น๋๊ธฐ ์์ ์ด ์งํ ์ค์ด๋ฉฐ, ์ฑ๊ณต ๋๋ ์คํจ ์ํ๋ก ์ ํ๋์ง ์์ ์ํ.
- Fulfilled ์ํ: ์์ ์ด ์ฑ๊ณตํ๋ฉด `.then()` ๋ฉ์๋๋ก ๊ฒฐ๊ณผ๊ฐ์ ์ฒ๋ฆฌ
- Rejected ์ํ: ์์ ์ด ์คํจํ๋ฉด `.catch()` ๋ฉ์๋๋ก ์ค๋ฅ ์ฒ๋ฆฌ
`.then()`์ผ๋ก ์ฑ๊ณต ์ฝ๋ฐฑ ์ฒ๋ฆฌ
new Promise((resolve, reject) => {
const produced = producing();
resolve(produced);
})
.then(produced => {
console.log(produced);
});
`.catch()`๋ก ์คํจ ์ฝ๋ฐฑ ์ฒ๋ฆฌ
new Promise((resolve, reject) => {
const produced = producing();
reject(produced);
})
.catch(error => {
console.log(error);
});
`.finally()`๋ก ์๋ฃ ์ฒ๋ฆฌ(์ฑ๊ณต /์คํจ ์๊ด ์์ด)
new Promise((resolve, reject) => {
const produced = '๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ค ์ค๋ฅ ๋ฐ์!';
reject(produced);
})
.catch(error => {
console.log('์คํจ:', error);
})
.finally(() => {
console.log('์์
์๋ฃ! (์ฑ๊ณต ์ฌ๋ถ์ ๊ด๊ณ์์ด ์คํ)');
});
Promise Hell (์ค์ฒฉ๋ Promise ๋ฌธ์ )
Promise๋ฅผ ์ค์ฒฉํด์ ์ฌ์ฉํ๋ค ๋ณด๋ฉด ์ฝ๋๊ฐ ๋ณต์กํด์ง๊ณ ์ ์ง๋ณด์๊ฐ ์ด๋ ค์์ง๋ค. Callback Hell๊ณผ ๋์ผํ๋ค.
step1(value1)
.then((value2) => {
step2(value2)
.then((value3) => {
step3(value3)
.then((value4) => {
console.log(value4);
});
});
});
Promise Chain: Promise Hell ํด๊ฒฐ ๋ฐฉ๋ฒ1.
Promise Chain์ ํ๋์ ๋น๋๊ธฐ ์์ ์ด ์๋ฃ๋ ํ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํ์ผ๋ก ๋ ๋ค๋ฅธ ๋น๋๊ธฐ ์์ ์ ์ํํ ๋ ์ ์ฉํ ํจํด์ด๋ค.
์ด ํจํด์ ํตํด ๊ฐ๋ฐ์๋ ์ฌ๋ฌ ๋น๋๊ธฐ ์์ ์ ์์ฐจ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์์ผ๋ฉฐ, ํ์ํ ์ ๋ณด๋ง ๋ฝ์์ ์ฒด๊ณ์ ์ผ๋ก ์ฌ์ฉ ํ ์ ์๋ค.
์์ ์ฝ๋(1)
step1(value1)
.then((value2) => {
return step2(value2);
})
.then((value3) => {
return step3(value3);
})
.then((value4) => {
console.log(value4);
});
์์ ์ฝ๋(2)
const fetchUser = (id) => new Promise((resolve, reject) => {
if (id === 1) {
resolve({ status: 200, user: { name: 'Aaron', age: 10 } })
} else {
reject({ status: 500, user: undefined })
}
})
const id = 1
const fetched_promise = fetchUser(id);
const redefined_promise = fetched_promise.then((result) => {
return { username: result.user.name, userage: result.user.age };
})
const parsed_promise = redefined_promise.then((redefined_user) => {
return { username: redefined_user.username };
})
fetchUser(id)
.then((user) => ({ username: user.name, userage: user.age }))
.then((redefined_user) => ({ username: redefined_user.username }))
fetchUser(id)
.then((user) => { console.log({ name: user.name }) })
fetchUser(id)
.then((user) => { console.log({ age: user.age }) })
fetchUser(id)
.then((user) => { console.log(true) })
์ ์์ ์ฝ๋์์ ์๋์ ๊ฐ์ด ํ์ํ ์ ๋ณด๋ง ๋ฝ์์ ์ฌ์ฉ ํ ์ ์๋ค.
fetchUser(id)
.then((user) => { console.log({ name: user.name }) })
fetchUser(id)
.then((user) => { console.log({ age: user.age }) })
fetchUser(id)
.then((user) => { console.log(true) })
โน๏ธ์ฐธ๊ณ
[ASAC 6๊ธฐ ๊ฐ์์๋ฃ]
https://velog.io/@jwo0o0/Javascript-%EB%8F%99%EA%B8%B0%EC%99%80-%EB%B9%84%EB%8F%99%EA%B8%B0
[Javascript] ์๋ฐ์คํฌ๋ฆฝํธ๊ฐ ๋น๋๊ธฐ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ - callback function, Promise, async/await
๋๊ธฐ vs. ๋น๋๊ธฐ ๐ก ๋๊ธฐ์ (synchronized) ๋๊ธฐ์ ์ด๋ผ๋ ๊ฒ์ ์์ ์์ ๊ณผ ์๋ฃ ์์ ์ด ๊ฐ์ ์ํฉ์ ๋งํ๋ค. > ์๋ฅผ ๋ค์ด, ๋๊ธฐ์ ์ธ ์นดํ์์ ์ง์ 1๋ช ์ด ์ฃผ๋ฌธ์ ๋ฐ์๋ค. ๐ง๐ป ์๋ A: ์์ด์ค ์นดํ๋ผ
velog.io
https://ko.javascript.info/callbacks
์ฝ๋ฐฑ
ko.javascript.info
https://medium.com/sjk5766/promise-hell%EA%B3%BC-promise-chain-73a3349d7f01
Promise hell๊ณผ Promise chain
์ต๊ทผ์ callback ๊ตฌ์กฐ๋ก ์๋ง์ธ ์์ค๋ฅผ Promise๋ก ๋ฆฌํฉํ ๋ง์ ํ์ต๋๋ค. ๊ทธ ๊ณผ์ ์์ Promise hell์ด ๋ฐ์ํ์๊ณ , ์ด๋ฅผ ์ด๋ป๊ฒ ํจ๊ณผ์ ์ธ Promise ๊ตฌ์กฐ๋ก ๊ฐ์ ํ ์ ์์๊น ์๋ํ๋ ๊ณผ์ ์ ์ ๋ฆฌํ์ต๋๋ค.
medium.com
https://ko.javascript.info/promise-chaining
ํ๋ผ๋ฏธ์ค ์ฒด์ด๋
ko.javascript.info
https://medium.com/cstech/asynchronous-programming-in-javascript-with-async-await-24b599a394cb
Asynchronous Programming in JavaScript with Async & Await
JavaScript is a scripting language primarily based on the concept of single-threaded execution.
medium.com
'๐ปDEV-STUDY > JavaScript' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
JavaScript ๊ฐ์ฒด ์ ์ ๋ฐ ์ฌ์ฉ๊ณผ JavaScript ๋ชจ๋ ์์คํ (0) | 2024.09.09 |
---|---|
JavaScript ํจ์ ๋ด this์ ๋ฉ์๋ ๋ด this ์ฐจ์ด (1) | 2024.09.09 |
JavaScript ํจ์ ์์ฑ ๋ฐฉ๋ฒ (1) | 2024.09.08 |
์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ ์ํ ๋ฐฉ์ = ํจ์ ์คํ ์๋ฆฌ (0) | 2024.09.05 |
JavaScript ๋ณ์, ํจ์ ์ ์ ๋ฐ ์ฌ์ฉ (0) | 2024.09.05 |