Using promises
Promise
๋ ๋น๋๊ธฐ ์์
์ ์ต์ข
์๋ฃ ๋๋ ์คํจ๋ฅผ ๋ํ๋ด๋ ๊ฐ์ฒด์
๋๋ค. ๋๋ถ๋ถ ์ฌ๋ฌ๋ถ์ ์ด๋ฏธ ๋ง๋ค์ด์ง promise๋ฅผ ์ฌ์ฉํ์๊ธฐ ๋๋ฌธ์ ์ด ๊ฐ์ด๋์์๋ ์ด๋ป๊ฒ promise๋ฅผ ๋ง๋๋์ง ์ค๋ช
ํ๊ธฐ์ ์์ promise์ ์ฌ์ฉ๋ฒ์ ๋ํด ์ค๋ช
ํฉ๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก promise๋ ํจ์์ ์ฝ๋ฐฑ์ ์ ๋ฌํ๋ ๋์ ์, ์ฝ๋ฐฑ์ ์ฒจ๋ถํ๋ ๋ฐฉ์์ ๊ฐ์ฒด์ ๋๋ค.
๋น๋๊ธฐ๋ก ์์ฑ ํ์ผ์ ์์ฑํด์ฃผ๋ createAudioFileAsync()
๋ผ๋ ํจ์๊ฐ ์์๋ค๊ณ ์๊ฐํด๋ณด์ธ์. ํด๋น ํจ์๋ ์์ฑ ์ค์ ์ ๋ํ ์ ๋ณด๋ฅผ ๋ฐ๊ณ , ๋ ๊ฐ์ง ์ฝ๋ฐฑ ํจ์๋ฅผ ๋ฐ์ต๋๋ค. ํ๋๋ ์์ฑ ํ์ผ์ด ์ฑ๊ณต์ ์ผ๋ก ์์ฑ๋์์๋ ์คํ๋๋ ์ฝ๋ฐฑ, ๊ทธ๋ฆฌ๊ณ ๋ค๋ฅธ ํ๋๋ ์๋ฌ๊ฐ ๋ฐ์ํ์๋ ์คํ๋๋ ์ฝ๋ฐฑ์
๋๋ค.
createAudioFileAsync()
๋ ํจ์๋ ์๋์ ๊ฐ์ด ์ฌ์ฉ๋ฉ๋๋ค.
function successCallback(result) {
console.log("Audio file ready at URL: " + result);
}
function failureCallback(error) {
console.log("Error generating audio file: " + error);
}
createAudioFileAsync(audioSettings, successCallback, failureCallback);
โฆ๋ชจ๋ํ ํจ์๋ค์ ์์ ๊ฐ์ด ์ฝ๋ฐฑ๋ค์ ์ ๋ฌํ์ง ์๊ณ ์ฝ๋ฐฑ์ ๋ถ์ฌ ์ฌ์ฉํ ์ ์๊ฒ Promise๋ฅผ ๋ฐํํด์ค๋๋ค.
๋ง์ฝ createAudioFileAsync()
ํจ์๊ฐ Promise๋ฅผ ๋ฐํํ๋๋ก ์์ ํ๋ค๋ฉด, ๋ค์๊ณผ ๊ฐ์ด ๊ฐ๋จํ๊ฒ ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
โฆ์กฐ๊ธ ๋ ๊ฐ๋จํ๊ฒ ์จ๋ณด์๋ฉด:
const promise = createAudioFileAsync(audioSettings);
promise.then(successCallback, failureCallback);
์ฐ๋ฆฌ๋ ์ด์ ๊ฐ์ ๊ฒ์ ๋น๋๊ธฐ ํจ์ ํธ์ถ์ด๋ผ๊ณ ๋ถ๋ฆ ๋๋ค. ์ด๋ฐ ๊ด๋ก๋ ๋ช ๊ฐ์ง ์ฅ์ ์ ๊ฐ๊ณ ์์ต๋๋ค. ๊ฐ๊ฐ์ ๋ํด ํ๋ฒ ์ดํด๋ณด๋๋ก ํฉ์๋ค.
Guarantees
์ฝ๋ฐฑ ํจ์๋ฅผ ์ ๋ฌํด์ฃผ๋ ๊ณ ์ ์ ์ธ ๋ฐฉ์๊ณผ๋ ๋ฌ๋ฆฌ, Promise๋ ์๋์ ๊ฐ์ ํน์ง์ ๋ณด์ฅํฉ๋๋ค.
- ์ฝ๋ฐฑ์ JavaScript Event Loop๊ฐ ํ์ฌ ์คํ์ค์ธ ์ฝ ์คํ์ ์๋ฃํ๊ธฐ ์ด์ ์๋ ์ ๋ ํธ์ถ๋์ง ์์ต๋๋ค.
- ๋น๋๊ธฐ ์์
์ด ์ฑ๊ณตํ๊ฑฐ๋ ์คํจํ ๋ค์
then()
์ ์ด์ฉํ์ฌ ์ถ๊ฐํ ์ฝ๋ฐฑ์ ๊ฒฝ์ฐ์๋ ์์ ๊ฐ์ต๋๋ค. then()
์ ์ฌ๋ฌ๋ฒ ์ฌ์ฉํ์ฌ ์ฌ๋ฌ๊ฐ์ ์ฝ๋ฐฑ์ ์ถ๊ฐ ํ ์ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ฐ๊ฐ์ ์ฝ๋ฐฑ์ ์ฃผ์ด์ง ์์๋๋ก ํ๋ ํ๋ ์คํ๋๊ฒ ๋ฉ๋๋ค.
Promise์ ๊ฐ์ฅ ๋ฐ์ด๋ ์ฅ์ ์ค์ ํ๋๋ chaining์ ๋๋ค.
Chaining
๋ณดํต ๋ ๊ฐ ์ด์์ ๋น๋๊ธฐ ์์ ์ ์์ฐจ์ ์ผ๋ก ์คํํด์ผ ํ๋ ์ํฉ์ ํํ ๋ณด๊ฒ ๋ฉ๋๋ค. ์์ฐจ์ ์ผ๋ก ๊ฐ๊ฐ์ ์์ ์ด ์ด์ ๋จ๊ณ ๋น๋๊ธฐ ์์ ์ด ์ฑ๊ณตํ๊ณ ๋์ ๊ทธ ๊ฒฐ๊ณผ๊ฐ์ ์ด์ฉํ์ฌ ๋ค์ ๋น๋๊ธฐ ์์ ์ ์คํํด์ผ ํ๋ ๊ฒฝ์ฐ๋ฅผ ์๋ฏธํฉ๋๋ค. ์ฐ๋ฆฌ๋ ์ด๋ฐ ์ํฉ์์ promise chain์ ์ด์ฉํ์ฌ ํด๊ฒฐํ๊ธฐ๋ ํฉ๋๋ค.
then()
ํจ์๋ ์๋ก์ด promise๋ฅผ ๋ฐํํฉ๋๋ค. ์ฒ์์ ๋ง๋ค์๋ promise์๋ ๋ค๋ฅธ ์๋ก์ด promise์
๋๋ค.
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
๋๋
const promise2 = doSomething().then(successCallback, failureCallback);
๋ ๋ฒ์งธ promise๋ doSomething()
๋ฟ๋ง ์๋๋ผ successCallback
or failureCallback
์ ์๋ฃ๋ฅผ ์๋ฏธํฉ๋๋ค. successCallback
or failureCallback
๋ํ promise๋ฅผ ๋ฐํํ๋ ๋น๋๊ธฐ ํจ์์ผ ์๋ ์์ต๋๋ค. ์ด ๊ฒฝ์ฐ promise2
์ ์ถ๊ฐ๋ ์ฝ๋ฐฑ์ successCallback
๋๋ failureCallback
์ ์ํด ๋ฐํ๋ promise ๋ค์ ๋๊ธฐํฉ๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก, ๊ฐ๊ฐ์ promise๋ ์ฒด์ธ ์์์ ์๋ก ๋ค๋ฅธ ๋น๋๊ธฐ ๋จ๊ณ์ ์๋ฃ๋ฅผ ๋ํ๋ ๋๋ค.
์์ ์๋ ์ฌ๋ฌ ๋น๋๊ธฐ ์์ ์ ์ฐ์์ ์ผ๋ก ์ํํ๋ฉด ๊ณ ์ ์ ์ธ '์ง์ฅ์ ์ฝ๋ฐฑ ํผ๋ผ๋ฏธ๋'๊ฐ ๋ง๋ค์ด ์ก์์ต๋๋ค.
doSomething(function (result) {
doSomethingElse(
result,
function (newResult) {
doThirdThing(
newResult,
function (finalResult) {
console.log("Got the final result: " + finalResult);
},
failureCallback,
);
},
failureCallback,
);
}, failureCallback);
๋ชจ๋ํ ๋ฐฉ์์ผ๋ก ์ ๊ทผํ๋ค๋ฉด, ์ฐ๋ฆฌ๋ ์ฝ๋ฐฑ ํจ์๋ค์ ๋ฐํ๋ promise์ promise chain์ ํ์ฑํ๋๋ก ์ถ๊ฐํ ์ ์์ต๋๋ค:
doSomething()
.then(function (result) {
return doSomethingElse(result);
})
.then(function (newResult) {
return doThirdThing(newResult);
})
.then(function (finalResult) {
console.log("Got the final result: " + finalResult);
})
.catch(failureCallback);
then
์ ๋๊ฒจ์ง๋ ์ธ์๋ ์ ํ์ (optional)์
๋๋ค. ๊ทธ๋ฆฌ๊ณ catch(failureCallback)
๋ then(null, failureCallback)
์ ์ถ์ฝ์
๋๋ค. ์ด ํํ์์ ํ์ดํ ํจ์๋ก ๋ํ๋ด๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
doSomething()
.then((result) => doSomethingElse(result))
.then((newResult) => doThirdThing(newResult))
.then((finalResult) => {
console.log(`Got the final result: ${finalResult}`);
})
.catch(failureCallback);
์ค์: ๋ฐํ๊ฐ์ด ๋ฐ๋์ ์์ด์ผ ํฉ๋๋ค, ๋ง์ฝ ์๋ค๋ฉด ์ฝ๋ฐฑ ํจ์๊ฐ ์ด์ ์ promise์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์ง ๋ชปํฉ๋๋ค. (ํ์ดํ ํจ์ () => x๋ () => {return x;}์ ๊ฐ์ต๋๋ค.)
Chaining after a catch
chain์์ ์์
์ด ์คํจํ ํ์๋ ์๋ก์ด ์์
์ ์ํํ๋ ๊ฒ์ด ๊ฐ๋ฅํ๋ฉฐ ๋งค์ฐ ์ ์ฉํฉ๋๋ค. (์ : catch
) ๋ค์ ์๋ฅผ ์ฝ์ผ์ญ์์ค:
new Promise((resolve, reject) => {
console.log("Initial");
resolve();
})
.then(() => {
throw new Error("Something failed");
console.log("Do this");
})
.catch(() => {
console.log("Do that");
})
.then(() => {
console.log("Do this, whatever happened before");
});
๊ทธ๋ฌ๋ฉด ๋ค์ ํ ์คํธ๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค.
Initial Do that Do this, whatever happened before
์ฐธ๊ณ : "Do this" ํ ์คํธ๊ฐ ์ถ๋ ฅ๋์ง ์์ ๊ฒ์ ์ฃผ์๊น๊ฒ ๋ณด์ญ์์ค. "Something failed" ์๋ฌ๊ฐ rejection์ ๋ฐ์์์ผฐ๊ธฐ ๋๋ฌธ์ ๋๋ค.
Error propagation
'์ฝ๋ฐฑ ์ง์ฅ'์์ failureCallback
์ด 3๋ฒ ๋ฐ์ํ ๊ฒ์ ๊ธฐ์ตํ ๊ฒ์
๋๋ค. promise chain์์๋ ๋จ ํ ๋ฒ๋ง ๋ฐ์ํ๋ ๊ฒ๊ณผ ๋น๊ต๋์ฃ .
doSomething()
.then((result) => doSomethingElse(result))
.then((newResult) => doThirdThing(newResult))
.then((finalResult) => console.log(`Got the final result: ${finalResult}`))
.catch(failureCallback);
๊ธฐ๋ณธ์ ์ผ๋ก promise chain์ ์์ธ๊ฐ ๋ฐ์ํ๋ฉด ๋ฉ์ถ๊ณ chain์ ์๋์์ catch๋ฅผ ์ฐพ์ต๋๋ค. ์ด๊ฒ์ ๋๊ธฐ ์ฝ๋๊ฐ ์ด๋ป๊ฒ ๋์ํ๋์ง ๋ชจ๋ธ๋ง ํ ๊ฒ์ ๋๋ค.
try {
const result = syncDoSomething();
const newResult = syncDoSomethingElse(result);
const finalResult = syncDoThirdThing(newResult);
console.log(`Got the final result: ${finalResult}`);
} catch (error) {
failureCallback(error);
}
๋น๋๊ธฐ ์ฝ๋๋ฅผ ์ฌ์ฉํ ์ด๋ฌํ ๋์นญ์ฑ์ ECMAScript 2017์์ async
/await
๊ตฌ๋ฌธ(Syntactic sugar) ์์ ์ต๊ณ ๋ก ๋๋ ์ ์์ต๋๋ค.
async function foo() {
try {
const result = await doSomething();
const newResult = await doSomethingElse(result);
const finalResult = await doThirdThing(newResult);
console.log(`Got the final result: ${finalResult}`);
} catch (error) {
failureCallback(error);
}
}
์ด๊ฒ์ promise๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํฉ๋๋ค. doSomething()
์ ์ด์ ํจ์์ ๊ฐ์ต๋๋ค. ๋ฌธ๋ฒ์ ์ด๊ณณ์์ ํ์ธํ ์ ์์ต๋๋ค.
Promise๋ ๋ชจ๋ ์ค๋ฅ๋ฅผ ์ก์๋ด์ด, ์์ธ ๋ฐ ํ๋ก๊ทธ๋๋ฐ ์ค๋ฅ๊ฐ ๋ฐ์ํด๋ ์ฝ๋ฐฑ ์ง์ฅ์ ๊ทผ๋ณธ์ ์ธ ๊ฒฐํจ์ ํด๊ฒฐํฉ๋๋ค. ์ด๋ ๋น๋๊ธฐ ์์ ์ ๊ธฐ๋ฅ ๊ตฌ์ฑ์ ํ์์ ์ ๋๋ค.
Promise rejection events
Promise๊ฐ reject๋ ๋๋ง๋ค ๋ ๊ฐ์ง ์ด๋ฒคํธ ์ค ํ๋๊ฐ ์ ์ญ ๋ฒ์์ ๋ฐ์ํฉ๋๋ค.(์ผ๋ฐ์ ์ผ๋ก, ์ ์ญ ๋ฒ์๋ window
๊ฑฐ๋, ์น ์์ปค์์ ์ฌ์ฉ๋๋ ๊ฒฝ์ฐ, Worker
, ํน์ ์์ปค ๊ธฐ๋ฐ ์ธํฐํ์ด์ค์
๋๋ค.) ๋ ๊ฐ์ง ์ด๋ฒคํธ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
rejectionhandled
-
executor์
reject
ํจ์์ ์ํด reject๊ฐ ์ฒ๋ฆฌ ๋ ํ promise๊ฐ reject ๋ ๋ ๋ฐ์ํฉ๋๋ค. unhandledrejection
-
promise๊ฐ reject๋์์ง๋ง ์ฌ์ฉํ ์ ์๋ reject ํธ๋ค๋ฌ๊ฐ ์์ ๋ ๋ฐ์ํฉ๋๋ค.
(PromiseRejectionEvent
์ ํ์ธ) ๋ ์ด๋ฒคํธ์๋ ๋ฉค๋ฒ ๋ณ์์ธ promise์ reason ์์ฑ์ด ์์ต๋๋ค. promise
๋ reject๋ promise๋ฅผ ๊ฐ๋ฆฌํค๋ ์์ฑ์ด๊ณ , reason
์ promise๊ฐ reject๋ ์ด์ ๋ฅผ ์๋ ค ์ฃผ๋ ์์ฑ์
๋๋ค.
์ด๋ค์ ์ด์ฉํด ํ๋ก๋ฏธ์ค์ ๋ํ ์๋ฌ ์ฒ๋ฆฌ๋ฅผ ๋์ฒด(fallback)ํ๋ ๊ฒ์ด ๊ฐ๋ฅํด์ง๋ฉฐ, ๋ํ ํ๋ก๋ฏธ์ค ๊ด๋ฆฌ์ ๋ฐ์ํ๋ ์ด์๋ค์ ๋๋ฒ๊น ํ๋ ๋ฐ ๋์์ ์ป์ ์ ์์ต๋๋ค. ์ด ํธ๋ค๋ฌ๋ค์ ๋ชจ๋ ๋งฅ๋ฝ์์ ์ ์ญ์ (global)์ด๊ธฐ ๋๋ฌธ์, ๋ชจ๋ ์๋ฌ๋ ๋ฐ์ํ ์ง์ (source)์ ์๊ด์์ด ๋์ผํ ํธ๋ค๋ฌ๋ก ์ ๋ฌ๋ฉ๋๋ค.
ํนํ ์ ์ฉํ ์ฌ๋ก : Node.js๋ก ์ฝ๋๋ฅผ ์์ฑํ ๋, ํํ ํ๋ก์ ํธ์์ ์ฌ์ฉํ๋ ๋ชจ๋์ด reject๋ ํ๋ก๋ฏธ์ค๋ฅผ ์ฒ๋ฆฌํ์ง ์์ ์ ์์ต๋๋ค. ์ด๋ฐ ๊ฒฝ์ฐ ๋
ธ๋ ์คํ ์ ์ฝ์์ ๋ก๊ทธ๊ฐ ๋จ์ต๋๋ค. ์ด๋ฅผ ์์ง์์ ๋ถ์ํ๊ณ ์ง์ ์ฒ๋ฆฌํ ์๋ ์์ต๋๋ค. ์๋๋ฉด ๊ทธ๋ฅ ์ฝ์ ์ถ๋ ฅ์ ์ด์ง๋ฝํ๋ ๊ฒ์ ๋ง๊ธฐ ์ํด ๊ทธ๋ด ์๋ ์์ฃ . ์ด๋ฐ ์์ผ๋ก unhandledrejection
(์์ด) ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ๋ ํธ๋ค๋ฌ๋ฅผ ์ถ๊ฐํ๋ฉด ๋ฉ๋๋ค.
window.addEventListener(
"unhandledrejection",
(event) => {
/* You might start here by adding code to examine the
promise specified by event.promise and the reason in
event.reason */
event.preventDefault();
},
false,
);
์ด๋ฒคํธ์ preventDefault()
๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด reject ๋ ํ๋ก๋ฏธ์ค๊ฐ ์ฒ๋ฆฌ๋์ง ์์์ ๋ JavaScript ๋ฐํ์์ด ๊ธฐ๋ณธ ๋์์ ์ํํ์ง ์์ต๋๋ค. ์ด ๊ธฐ๋ณธ ๋์์ ๋๊ฐ ์ฝ์์ ์ค๋ฅ๋ฅผ ๊ธฐ๋กํ๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์, ์ด๊ฒ์ ํ์คํ NodeJS๋ฅผ ์ํ ๊ฒ์ด์ฃ .
์ ๋๋ก ํ๋ ค๋ฉด, ๋น์ฐํ ๋ง์ด์ง๋ง, ์ด ์ด๋ฒคํธ๋ฅผ ๊ทธ๋ฅ ๋ฌด์ํด๋ฒ๋ฆฌ๊ธฐ ์ ์ reject๋ ํ๋ก๋ฏธ์ค ์ฝ๋์ ์ค์ ๋ก ๋ฒ๊ทธ๊ฐ ์๋์ง ํ์คํ ๊ฒ์ฌํด์ผ ํฉ๋๋ค.
์ค๋๋ ์ฝ๋ฐฑ API๋ฅผ ์ฌ์ฉํ์ฌ Promise๋ง๋ค๊ธฐ
Promise
๋ ์์ฑ์๋ฅผ ์ฌ์ฉํ์ฌ ์ฒ์๋ถํฐ ์์ฑ ๋ ์ ์์ต๋๋ค. ์ด๊ฒ์ ์ค๋๋ API๋ฅผ ๊ฐ์ ๋๋ง ํ์ํฉ๋๋ค.
์ด์์ ์ธ ํ๋ก๊ทธ๋๋ฐ ์ธ๊ณ์์๋ ๋ชจ๋ ๋น๋๊ธฐ ํจ์๋ promise์ ๋ฐํํด์ผ ํ์ง๋ง, ๋ถํํ๋ ์ผ๋ถ API๋ ์ฌ์ ํ success ๋ฐ / ๋๋ failure ์ฝ๋ฐฑ์ ์ ๋ฌํ๋ ๋ฐฉ์์ผ๊ฑฐ๋ผ ์๊ฐํฉ๋๋ค. ์๋ฅผ ๋ค๋ฉด setTimeout ()
ํจ์๊ฐ ์์ต๋๋ค.
setTimeout(() => saySomething("10 seconds passed"), 10000);
์์ ์คํ์ผ์ ์ฝ๋ฐฑ๊ณผ Promise๋ฅผ ํฉ์น๋ ๊ฒ์ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ํจ์ saySomething()
์ด ์คํจํ๊ฑฐ๋ ํ๋ก๊ทธ๋๋ฐ ์ค๋ฅ๊ฐ ์์ผ๋ฉด ์๋ฌด ๊ฒ๋ ์ก์ ๋ด์ง ์์ต๋๋ค. setTimeout
์ ๋ฌธ์ ์ ์
๋๋ค.
๋คํํ๋ ์ฐ๋ฆฌ๋ setTimeout
์ Promise๋ก ๊ฐ์ ์ ์์ต๋๋ค. ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ ๊ฐ๋ฅํ ๊ฐ์ฅ ๋ฎ์ ์์ค์์ ๋ฌธ์ ๊ฐ ๋๋ ํจ์๋ฅผ ๊ฐ์ผ ๋ค์ ๋ค์๋ ์ง์ ํธ์ถํ์ง ์๋ ๊ฒ์
๋๋ค.
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
wait(10000)
.then(() => saySomething("10 seconds"))
.catch(failureCallback);
๊ธฐ๋ณธ์ ์ผ๋ก promise constructor๋ promise๋ฅผ ์ง์ ํด๊ฒฐํ๊ฑฐ๋ reject ํ ์ ์๋ ์คํ์ ํจ์๋ฅผ ์ฌ์ฉํฉ๋๋ค. setTimeout()
์ ํจ์์์ fail์ด ์ผ์ด๋๊ฑฐ๋ error๊ฐ ๋ฐ์ํ์ง ์๊ธฐ ๋๋ฌธ์ ์ด ๊ฒฝ์ฐ reject๋ฅผ ์ฌ์ฉํ์ง ์์ต๋๋ค.
Composition
Promise.resolve ()
์ Promise.reject ()
๋ ๊ฐ๊ฐ ์ด๋ฏธ resolve๋๊ฑฐ๋ reject ๋ promise๋ฅผ ์ฌ๋ฌ๋ถ์ด ์ง์ ์์ฑํ๊ธฐ์ํ ๋ฐ๋ก ๊ฐ๊ธฐ์
๋๋ค. ๊ฐ๋ ์ ์ฉํ๊ฒ ์ฌ์ฉ๋ฉ๋๋ค.
Promise.all()
์ Promise.race()
๋ ๋น๋๊ธฐ ์์
์ ๋ณ๋ ฌ๋ก ์คํํ๊ธฐ์ํ ๋ ๊ฐ์ง ๊ตฌ์ฑ ๋๊ตฌ์
๋๋ค.
์ฐ๋ฆฌ๋ ๋ณ๋ ฌ๋ก ์์ ์ ์์ํ๊ณ ๋ค์๊ณผ ๊ฐ์ด ๋ชจ๋ ์๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆด ์ ์์ต๋๋ค.
Promise.all([func1(), func2(), func3()]).then(([result1, result2, result3]) => {
/* use result1, result2 and result3 */
});
๊ณ ๊ธ์ง JavaScript๋ฅผ ์ฌ์ฉํ์ฌ ์์ฐจ์ ๊ตฌ์ฑ์ด ๊ฐ๋ฅํฉ๋๋ค.
[func1, func2, func3]
.reduce((p, f) => p.then(f), Promise.resolve())
.then((result3) => {
/* use result3 */
});
๊ธฐ๋ณธ์ ์ผ๋ก, ์ฐ๋ฆฌ๋ ๋น๋๊ธฐ ํจ์ ๋ฐฐ์ด์ ๋ค์๊ณผ ๊ฐ์ promise ์ฒด์ธ์ผ๋ก ์ค์
๋๋ค. Promise.resolve().then(func1).then(func2).then(func3);
์ด๊ฒ์ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ํฉ์ฑ ํจ์๋ก ๋ง๋ค ์ ์๋๋ฐ, ์ด๋ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์์ ์ผ๋ฐ์ ์ธ ๋ฐฉ์์ ๋๋ค.
const applyAsync = (acc, val) => acc.then(val);
const composeAsync =
(...funcs) =>
(x) =>
funcs.reduce(applyAsync, Promise.resolve(x));
composeAsync()
ํจ์๋ ์ฌ๋ฌ ํจ์๋ฅผ ์ธ์๋ก ๋ฐ์๋ค์ด๊ณ composition ํ์ดํ ๋ผ์ธ์ ํตํด ์ ๋ฌ๋๋ ์ด๊ธฐ ๊ฐ์ ํ์ฉํ๋ ์ ํจ์๋ฅผ ๋ฐํํฉ๋๋ค.
const transformData = composeAsync(func1, func2, func3);
const result3 = transformData(data);
ECMAScript 2017์์๋ async / await๋ฅผ ์ฌ์ฉํ์ฌ ์์ฐจ์ ๊ตฌ์ฑ์ ๋ณด๋ค ๊ฐ๋จํ๊ฒ ์ํํ ์ ์์ต๋๋ค.
let result;
for (const f of [func1, func2, func3]) {
result = await f(result);
}
/* use last result (i.e. result3) */
Timing
๋๋ผ์(์ญ์ ์ฃผ. ์๋ฌ๊ฐ ๋๋ค๊ฑฐ๋, ์ฝ๋๊ฐ ๋ฌธ์ ๊ฐ ์๊ธด๋ค๊ฑฐ๋..ํ์๋์ ๊ทธ ๋๋ผ์..)์ ํผํ๊ธฐ ์ํด then()
์ ์ ๋ฌ๋ ํจ์๋ already-resolved promise์ ์๋ ๊ฒฝ์ฐ์๋ ๋๊ธฐ์ ์ผ๋ก ํธ์ถ๋์ง ์์ต๋๋ค.
Promise.resolve().then(() => console.log(2));
console.log(1); // 1, 2
์ฆ์ ์คํ๋๋ ๋์ ์ ๋ฌ๋ ํจ์๋ ๋ง์ดํฌ๋ก ํ์คํฌ ๋๊ธฐ์ด์ ์ ์ฅ๋ฉ๋๋ค. ์ฆ, ์๋ฐ ์คํฌ๋ฆฝํธ ์ด๋ฒคํธ ๋ฃจํ์ ํ์ฌ ์คํ์ด ๋๋๊ณ , ๋๊ธฐ์ด๋ ๋น์ด์์ ๋์ ์ ์ด๊ถ์ด ์ด๋ฒคํธ ๋ฃจํ๋ก ๋ฐํ๋๊ธฐ ์ง์ ์ ์คํ๋ฉ๋๋ค.
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
wait().then(() => console.log(4));
Promise.resolve()
.then(() => console.log(2))
.then(() => console.log(3));
console.log(1); // 1, 2, 3, 4
Nesting
๊ฐ๋จํ promise ์ฒด์ธ์ ํํํ๊ฒ ์ ์งํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ข์ต๋๋ค. ์ค์ฒฉ๋ ์ฒด์ธ์ ๋ถ์ฃผ์ํ ๊ตฌ์ฑ์ ๊ฒฐ๊ณผ์ผ ์ ์์ต๋๋ค. common mistakes๋ฅผ ์ฐธ์กฐํ์ญ์์ค.
์ค์ฒฉ์ catch
๋ฌธ ๋ฒ์๋ฅผ ์ ํํ๋ ์ ์ด ๊ตฌ์กฐ์
๋๋ค. ํนํ, ์ค์ฒฉ๋ catch
๋ ์ค์ฒฉ๋ ๋ฒ์ ์ธ๋ถ์ ์ฒด์ธ์ ์๋ ์ค๋ฅ๊ฐ ์๋ ๋ฒ์ ๋ฐ ๊ทธ ์ดํ์ ์ค๋ฅ๋ง ์ก์ต๋๋ค. ์ฌ๋ฐ๋ฅด๊ฒ ์ฌ์ฉํ๋ฉด ์ค๋ฅ ๋ณต๊ตฌ ์ ๋ ์ ํํ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค.
doSomethingCritical()
.then((result) =>
doSomethingOptional(result)
.then((optionalResult) => doSomethingExtraNice(optionalResult))
.catch((e) => {}),
) // Ignore if optional stuff fails; proceed.
.then(() => moreCriticalStuff())
.catch((e) => console.log("Critical failure: " + e.message));
์ฌ๊ธฐ์ ์๋ ์ ํ์ ๋จ๊ณ๋ ๋ค์ฌ ์ฐ๊ธฐ๊ฐ ์๋ ์ค์ฒฉ๋์ด ์์ง๋ง ์ฃผ์์ ๋ฐ๊นฅ ์ชฝ (
๋ฐ )
์ ๊ท์น์ ์ด์ง ์์ ๋ฐฐ์น๋ฅผ ํ์ง์๋๋ก ์กฐ์ฌํ์ธ์.
inner neutralizing catch
๋ฌธ์ doSomethingOptional()
๋ฐ doSomethingExtraNice()
์์ ๋ฐ์ํ ์ค๋ฅ๋ฅผ catch ํ ํ์ ์ฝ๋๊ฐ moreCriticalStuff()
๋ก ๋ค์ ์์๋ฉ๋๋ค. ์ค์ํ ๊ฒ์ doSomethingCritical()
์ด ์คํจํ๋ฉด ํด๋น ์ค๋ฅ๋ ์ต์ข
(์ธ๋ถ) catch
์์๋ง ํฌ์ฐฉ๋๋ค๋ ๊ฒ์
๋๋ค.
Common mistakes
promise chains์ ์์ฑํ ๋ ์ฃผ์ํด์ผ ํ ๋ช ๊ฐ์ง ์ผ๋ฐ์ ์ธ ์ค์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. ์ด๋ฌํ ์ค์ ์ค ๋ช ๊ฐ์ง๋ ๋ค์ ์์ ์์ ๋ํ๋ฉ๋๋ค.
// Bad example! Spot 3 mistakes!
doSomething()
.then(function (result) {
doSomethingElse(result) // Forgot to return promise from inner chain + unnecessary nesting
.then((newResult) => doThirdThing(newResult));
})
.then(() => doFourthThing());
// Forgot to terminate chain with a catch!
์ฒซ ๋ฒ์งธ ์ค์๋ ์ ๋๋ก ์ฒด์ธ์ ์ฐ๊ฒฐํ์ง ์๋ ๊ฒ์
๋๋ค. ์ด๊ฒ์ ์ฐ๋ฆฌ๊ฐ ์๋ก์ด promise๋ฅผ ๋ง๋ค์์ง๋ง ๊ทธ๊ฒ์ ๋ฐํํ๋ ๊ฒ์ ์์์ ๋ ์ผ์ด๋ฉ๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ์ฒด์ธ์ด ๋์ด์ง๊ฑฐ๋ ์คํ๋ ค ๋ ๊ฐ์ ๋
๋ฆฝ์ ์ธ ์ฒด์ธ์ด ๊ฒฝ์ํ๊ฒ ๋ฉ๋๋ค. ์ฆ, doFourthThing()
์ doSomethingElse()
๋๋ doThirdThing()
์ด ์๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ์ฐ๋ฆฌ๊ฐ ์๋ํ์ง ์์์ง๋ง ์ด๋ค๊ณผ ๋ณ๋ ฌ๋ก ์คํ๋ฉ๋๋ค. ๋ํ ๋ณ๋์ ์ฒด์ธ์ ๋ณ๋์ ์ค๋ฅ ์ฒ๋ฆฌ ๊ธฐ๋ฅ์ ๊ฐ์ง๊ณ ์์ด์ ์ก๊ธฐ ์ด๋ ค์ด ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
๋ ๋ฒ์งธ ์ค์๋ ๋ถํ์ํ๊ฒ ์ค์ฒฉ๋์ด ์ฒซ ๋ฒ์งธ ์ค์๋ฅผ ๊ฐ๋ฅํ๊ฒ ๋ง๋๋ ๊ฒ์ ๋๋ค. ๋ํ ์ค์ฒฉ์ ๋ด๋ถ ์ค๋ฅ ์ฒ๋ฆฌ๊ธฐ์ ๋ฒ์๋ฅผ ์ ํํ๋ฉฐ, ์๋ํ์ง ์์ ์๋ฌ๊ฐ ์บ์น๋์ง ์๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ์ด ๋ณํ์ promise constructor anti-pattern์ ๋๋ค. ์ด ํจํด์ ์ด๋ฏธ ์ฝ์์ ์ฌ์ฉํ๋ ์ฝ๋๋ฅผ ๊ฐ์ธ๊ธฐ ์ํด promise ์์ฑ์์ ์ค๋ณต ์ฌ์ฉ๊ณผ ์ค์ฒฉ์ ๊ฒฐํฉํฉ๋๋ค.
์ธ ๋ฒ์งธ ์ค์๋ catch
๋ก ์ฒด์ธ์ ์ข
๋ฃํ๋ ๊ฒ์ ์๋ ๊ฒ์
๋๋ค. ์ข
๋ฃ๋์ง ์์ promise ์ฒด์ธ์ ๋๋ถ๋ถ์ ๋ธ๋ผ์ฐ์ ์์ ์์ํ์ง ๋ชปํ promise rejection์ ์ด๋ํฉ๋๋ค.
์ข์ ๊ฒฝํ ๋ฒ์น์ ํญ์ promise ์ฒด์ธ์ ๋ฐํํ๊ฑฐ๋ ์ข ๊ฒฐํ๋ ๊ฒ์ด๋ฉฐ, ์๋ก์ด promise๋ฅผ ์ป์๋ง์ ์ฆ์ ๋ฐํํ์ฌ ๋ณต์ก๋๋ฅผ ๋ฎ์ถ๋ ๊ฒ์ ๋๋ค.
doSomething()
.then(function (result) {
return doSomethingElse(result);
})
.then((newResult) => doThirdThing(newResult))
.then(() => doFourthThing())
.catch((error) => console.log(error));
() => x
์ () => { return x; }
์ ์ถ์ฝํ์์ ์ฐธ๊ณ ํ์ธ์.
์ด์ ์ฐ๋ฆฌ๋ ์ ์ ํ ์ค๋ฅ ์ฒ๋ฆฌ ๊ธฐ๋ฅ์ ๊ฐ์ถ ๊ฒฐ์ ์ฑ์๋ ๋จ์ผ ์ฒด์ธ์ด ์์ต๋๋ค.
async
/await
๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ถ๋ถ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค. ์ด๋ฌํ ๋ฌธ๋ฒ์ ๊ฐ์ฅ ํํ ์ค์๋ await
ํค์๋๋ฅผ ๋นผ๋จน๋ ๊ฒ์
๋๋ค.
promise์ ์์ ์ด ์ถฉ๋ํ ๋
์์ธกํ ์ ์๋ ์์๋ก ์คํ๋๋ promise ๋ฐ ์์ (์: ์ด๋ฒคํธ ๋๋ ์ฝ๋ฐฑ)์ด ์๋ ์ํฉ์ ์ง๋ฉดํ๋ฉด ๋ง์ดํฌ๋ก ํ์คํฌ๋ฅผ ์ฌ์ฉํ์ฌ ์ํ๋ฅผ ํ์ธํ๊ฑฐ๋ promise๊ฐ ์กฐ๊ฑด๋ถ๋ก ์์ฑ๋ ๋ promise์ ๊ท ํ์ ๋ง์ถ๋ ๊ฒ์ด ์ข์ต๋๋ค.
๋ง์ดํฌ๋ก ํ์คํฌ๊ฐ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐ ๋์์ด ๋ ์ ์๋ค๊ณ ์๊ฐ๋๋ฉด, queueMicrotask()๋ฅผ ์ฌ์ฉํด์ ํจ์๋ฅผ ๋ง์ดํฌ๋ก ํ์คํฌ๋ก ๋๊ธฐ์ด์ ๋ฃ๋ ๋ฐฉ๋ฒ์ ๋ง์ดํฌ๋ก ํ์คํฌ ๊ฐ์ด๋์์ ์์ธํ ์์๋ณด์ญ์์ค.