3. Async/await Internals
promise๋ async/await์ ํตํฉ์ ์ํ ๊ธฐ๋ณธ์ ์ธ ์๋จ์
๋๋ค. promise๊ฐ ์ด๋ป๊ฒ ์๋ํ๋์ง ์์ ๋ถํฐ ์์๋ณด์์ผ๋ ์ด์ ์์ผ๋ฅผ ๋ํ์ promise์ await
์ ์ ์ฉํ ๋ ์ด๋ค ์ผ์ด ์ผ์ด๋๋์ง ์ดํด๋ด
์๋ค. ๋น๋ก async ํจ์๊ฐ ๋๊ธฐ์ ํจ์์ ์ ์ฌํ๊ฒ ๋ณด์ด์ง๋ง, ๊ทธ ์ด๋ฉด์ callbacks์ผ๋ก ๊ฐ๋ ์ฑ์์ง ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋์ฒ๋ผ ๋น๋๊ธฐ์ ์
๋๋ค. ์ด๋ฏธ ์ง์ํ๊ฒ ์ง๋ง, await
์ ์๋ฐ์คํฌ๋ฆฝํธ๋ก ํ์ฌ๊ธ ๋ด๋ถ์ ์ผ๋ก then()
ํจ์๋ฅผ ํธ์ถํ๋๋ก ํฉ๋๋ค.
// example 3.1
const p = {
then: (onFulfilled) => {
// ๋ค์์ "then(): function () { [native code] }"๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
console.log("then():", onFulfilled.toString());
// ์ค๋ฅ ์คํ์๋ ํ๊ฐ์ง ์ํธ๋ฆฌ๋ฉด ๋์ต๋๋ค.
// Error
// at Object.then (/examples/chapter3.test.js:8:21)
console.log(new Error().stack);
onFulfilled("Hello, World!");
},
};
console.log(await p); // "Hello, World!"๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
await
ํค์๋๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ก ํ์ฌ๊ธ ์ด๋ฒคํธ ๋ฃจํ์ ๋ค์ ์ฐจ๋ก๊น์ง ์คํ์ ์ผ์ ์ ์ง ์ํค๋๋ก ํฉ๋๋ค. ์๋ ์ฝ๋์์ await ์ดํ, console.log()
๋ ++currentId
์ฝ๋ ๋ค์ ์คํ๋ฉ๋๋ค.
// example 3.2
const startId = 0;
let currentId = 0;
process.nextTick(() => ++currentId);
const p = {
then: (onFulfilled) => {
console.log("then():", currentId - startId); // "then(): 1"
onFulfilled("Hello, World!");
},
};
console.log("Before:", currentId - startId); // "Before: 0"
await p;
console.log("After:", currentId - startId); // "After: 1"
๋น๋ก then()
์ด ์์ ๋๊ธฐ์์ด๋ผ๋ ๋ค์ ์ฐจ๋ก์ ์๋๋๋ค๋ ์ ์ ์ ์ํ์ธ์. ์ด๊ฒ์ await
๋ ์ต์ํ ๋ค์ ์ฐจ๋ก๊น์ง๋ ์คํ์ ์ผ์ ์ ์ง ์ํจ๋ค๋ ๊ฒ์ ๋ปํฉ๋๋ค. ๋ง์ฝ onRejected(err)
๋ฅผ ํธ์ถํ๋ค๋ฉด await
ํค์๋๋ ์ฌ๋ฌ๋ถ ํจ์ ๋ณธ์ฒด๋ก err
๋ฅผ throwsํฉ๋๋ค.
// example 3.3
const startId = 0;
let currentId = 0;
process.nextTick(() => ++currentId);
const p = {
then: (onFulfilled, onRejected) => {
console.log("then():", currentId - startId); // "then(): 1
return onRejected(Error("Oops!"));
},
};
try {
console.log("Before:", currentId - startId); // "Before: 0"
await p;
console.log("This does not print");
} catch (error) {
console.log("After:", currentId - startId); // "After: 1"
}
await vs return
async ํจ์์์ return
์ ๊ทธ ํจ์๊ฐ ๋ฐํํ๋ promise๋ฅผ "ํด๊ฒฐ" ํ๋ค๋ ๊ฒ์ ๊ธฐ์ตํ์ธ์. ์ด๊ฒ์ ์ฌ๋ฌ๋ถ์ด promise๋๋ฅผ return
ํ ์ ์๋ค๋ ๊ฒ์ ๋ปํฉ๋๋ค. await
์ return
์ ์ฐจ์ด์ ์ ๋ฌด์์๊น์? ๋ต์ ์ด๋ ์ต๋๋ค. promise์ await
ํ ๊ฒฝ์ฐ, ์๋ฐ์คํฌ๋ฆฝํธ๋ ๊ทธ async ํจ์์ ์คํ์ ์ผ ์์ ์ง์ํจ ํ์ ์ฌ๊ฐ์ํค์ง๋ง, promise๋ฅผ return
ํ๋ค๋ฉด ๊ทธ async ํจ์์ ์ํ์ ์ข
๋ฃํด ๋ฒ๋ฆฌ๊ณ return๋ ํจ์๋ฅผ ์ฌ๊ฐํ์ง ์์ต๋๋ค.
๋ต์ ๋ถ๋ช
๋ง์ง๋ง, await
๊ฐ ์ด๋ป๊ฒ ์๋ํ๋์ง ์์๋ด๊ธฐ์๋ ์๋ฏธ๊ฐ ์ข ํจ์ถ์ ์
๋๋ค. ์ฌ๋ฌ๋ถ์ด await p
๋ฅผ try/catch
๋ก ๊ฐ์ธ๊ณ p
๋ฅผ "๊ฑฐ์ " ์ฒ๋ฆฌํ๋ฉด error๋ฅผ catchํ ์ ์์ต๋๋ค. ๊ทธ๋์ return p
ํ๋ค๋ฉด ์ด๋จ๊น์?
// example 3.4
async function test() {
try {
return Promise.reject(new Error("Oops!"));
} catch (error) {
return "ok";
}
}
// "Oops!"๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค.
test().then(
(v) => console.log(v),
(err) => console.log(err.message)
);
try/catch
๋ ์ฌ๋ฌ๋ถ์ด returnํ "๊ฑฐ์ "ํ promise๋ฅผ catch ํ์ง ๋ชปํ๋ค๋ ์ ์ ์ฃผ๋ชฉํ๊ธฐ ๋ฐ๋๋๋ค. promise๊ฐ "๊ฑฐ์ "์ผ ๋, ์ await
๋ง์ด error๋ฅผ catch ํ ๊น์? ๊ทธ๊ฒ์ await๋
์คํ์ ์ฌ๊ฐํ ๋ error๋ฅผ throw ํ๊ธฐ ๋๋ฌธ์
๋๋ค. promise๋ฅผ return
ํ๋ฉด ์๋ฐ์คํฌ๋ฆฝํธ๋ ์ฌ๋ฌ๋ถ์ async ํจ์ ๋ณธ์ฒด์ ์คํ์ ๋ฉ์ถ๊ณ ์ด async ํจ์์ promise์ ๋ํด resolve()
๋ฅผ ์ํํด ๋ฒ๋ฆฝ๋๋ค.
๋ฐ๋ฉด์ promise์ await
์ ํ๋ฉด, ์๋ฐ์คํฌ๋ฆฝํธ๋ ๊ทธ async ํจ์์ ์คํ์ ์ผ์ ์ ์ง ์ํค๊ณ ๊ทธ promise๊ฐ "์ ์ฐฉ"๋๋ฉด ๋ค์ ์ฌ๊ฐํฉ๋๋ค. await
์ดํ, ์๋ฐ์คํฌ๋ฆฝํธ๊ฐ ์ฌ๋ฌ๋ถ์ async ํจ์๋ฅผ ์ฌ๊ฐํ ๋, ๋ง์ฝ await ํ promise๊ฐ "๊ฑฐ์ " ์ํ๋ฉด ๊ทธ ๊ทธ ๊ฑฐ์ ๊ฐ์ธ error๋ฅผ ๋์ง๋ ๊ฒ์
๋๋ค. ์๋๋ promise์ await ํ ๊ฒฝ์ฐ ์ด๋ค ์ผ์ด ๋ฐ์ํ๋์ง ๋ณด์ฌ์ฃผ๊ณ ์์ต๋๋ค.

๋ฐ๋ฉด์, aync ํจ์์์ promise๋ฅผ return
ํ ๋, ์ฌ๋ฌ๋ถ์ ๊ทธ promise๋ ์๋ฐ์คํฌ๋ฆฝํธ ์คํ ํ๊ฒฝ์ผ๋ก ๊ฐ๋ฒ๋ฆฌ๊ณ ๋ค์ ์ฝ๋๋ก ๋์์ค์ง ๋ชปํฉ๋๋ค. ๊ทธ๋์ example 3.4์์ try/catch
๊ฐ error๋ฅผ ๋ค๋ฃจ์ง ๋ชปํ ๊ฒ์
๋๋ค. ์๋ ์๋ค์ error๋ฅผ catch
ํ๋ ๋ช ๊ฐ์ง ๋์๋ค์
๋๋ค. example 3.5๋ await p
๊ฒฐ๊ณผ๋ฅผ v
๋ณ์์ ํ ๋นํ๊ณ ๊ทธ ๋ณ์๋ฅผ ๋ฐํํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ example 3.6์ return await
๋ฅผ ์ด์ฉํฉ๋๋ค.
// example 3.5
async function test() {
try {
const v = await Promise.reject(new Error("Oops!"));
return v;
} catch (error) {
return "ok";
}
}
// Prints "ok"
test().then(
(v) => console.log(v),
(err) => console.log(err.message)
);
// example 3.6
async function test() {
try {
return await Promise.reject(new Error("Oops!"));
} catch (error) {
return "ok";
}
}
// Prints "ok"
test().then(
(v) => console.log(v),
(err) => console.log(err.message)
);
๋ ๊ฐ์ง ์ ๊ทผ๋ฒ ๋ชจ๋ ์ ์๋ํฉ๋๋ค. ํ์ง๋ง example 3.5๊ฐ ์ข ๋ ๋จ์ํ๊ณ ํผ๋์ด ์ ์ต๋๋ค. return await
์ ์๋ฐ์คํฌ๋ฆฝํธ ๋น์ ๋ฌธ๊ฐ์๊ฒ๋ ๋ค์ ์ด๋ ต๊ฒ ๋๊ปด์ง๋๋ค. ๊ทธ๋์ ์ผ๋ฐ ๊ฐ๋ฐ์๊ฐ ๋น๋๊ธฐ ์ฝ๋๋ฅผ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๋๋ก ํ์๋ ๋ชฉ์ ์์ ์ด์ง ๋ฒ์ด๋ฉ๋๋ค.
Concurrency: ๋์์ฑ
์ด์ , await p
๊ฐ ์๋ฐ์คํฌ๋ฆฝํธ๋ก ํ์ฌ๊ธ ์ฌ๋ฌ๋ถ์ async ํจ์๋ฅผ ์ผ์ ์ ์ง ์ํค๊ณ p.then()
๋ฅผ ํธ์ถํ๋ค๋ ๊ฒ์ ์์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ promise๊ฐ "์ ์ฐฉ"๋ ๋ ์ํ์ ์ฌ๊ฐํ๋ค๋ ๊ฒ๋์ ์์์ต๋๋ค. ๊ทธ๋ ๋ค๋ฉด ์ฌ๋ฌ async ํจ์๋ค์ด ๋ณ๋ ฌ๋ก ์ํ๋ ๋๋ ์ด๊ฒ์ ์ด๋ค ์๋ฏธ๋ฅผ ๊ฐ์ง๊น์?
"์๋ฐ์คํฌ๋ฆฝํธ๋ ๋จ์ผ ์ค๋ ๋ ๋ฐฉ์์ด๋ค" ๋ผ๋ ๊ฐ๋
์ ๋ณดํต์ ์๋ฐ์คํฌ๋ฆฝํธ ํจ์๊ฐ ์ํ ์ค์ผ ๋, ๋ค๋ฅธ ์๋ฐ์คํฌ๋ฆฝํธ๋ ๋์ํ์ง ์๋๋ค๋ ๊ฒ์ ๋ปํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ์๋ ์ฝ๋๋ ์๋ฌด๊ฒ๋ ์ถ๋ ฅํ์ง ์์ต๋๋ค. ๋ค๋ฅธ ์ธ์ด๋ค ์์ setImmediate()
๊ฐ์ ๊ตฌ์กฐ๋ ๋ถ๋ฆฌ๋ ์ค๋ ๋์์ ๋ก์ง์ ์ํํ๊ณ ๋ฌดํ ๋ฃจํ๊ฐ ์ํ๋๋ ๋์์๋ ์ถ๋ ฅ์ ํ์ง๋ง ์๋ฐ์คํฌ๋ฆฝํธ๋ ์ด๊ฒ์ ํ์ฉํ์ง ์์ต๋๋ค.
// example 3.7
setImmediate(() => console.log("Hello, World!"));
// ๋ค์์ ๋ฌดํ ๋ฃจํ์ ๋น ์ง๋๋ค. ๊ทธ๋์ ์ด๋ฒคํธ ๋ฃจํ๋ก ๋์๊ฐ์ง ๋ชปํ๋ฏ๋ก
// ์ ์ฝ๋ฐฑ์ console.log๋ ๊ฒฐ์ฝ ์๋ํ์ง ์์ต๋๋ค.
while (true) {}
์๋ฐ์คํฌ๋ฆฝํธ ํจ์๋ค์ ๋ฌผ๋ฆฌํ์ "ํ์ธ๋ฆฌ์ ๋ฒ ํ์๋ฆฌ"์ ๊ฐ์ต๋๋ค. ์ด๋ค ๋ ๊ฐ์ ์ผ๋ฐ์ ์ธ ์๋ฐ์คํฌ๋ฆฝํธ ํจ์๋ค๋ ๋์์ ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์์ ๋์ํ ์ ์์ต๋๋ค. ํด๋ก์ ธ(์ฝ๋ฐฑ)๋ค์ ๋ถ๋ฆฌ๋ ํจ์๋ค์
๋๋ค. ๊ทธ๋์ ์๋ foo(), bar()
๊ทธ๋ฆฌ๊ณ baz()
ํจ์๋ค์ ๋ชจ๋ ๋ถ๋ฆฌ๋์ด ๋์ํฉ๋๋ค.
// example 3.8
function foo() {
let x = 0;
// foo()๋ฅผ ๋ง์น๊ณ , bar()๊ฐ ํ์ ์คํ๋๋๋ผ๋ ์ฌ์ ํ x๋ฅผ ์ด์ฉํ ์ ์์ต๋๋ค.
setImmediate(bar);
// baz()๊ฐ ๋ง์น ๋๊น์ง foo() ์คํ์ด ์ค๋จ๋ฉ๋๋ค
baz();
function bar() {
++x;
}
function baz() {
++x;
}
}
๋น๋๊ธฐ ํจ์๋ค๋ ๊ฐ์ ๊ท์น์ ๋ฐ๋ฆ ๋๋ค: ์ด๋ค ๋ ํจ์๋ ๋์์ ๋์ํ ์ ์์ต๋๋ค. ํ์ง๋ง ๋ฉ๋ชจ๋ฆฌ๋ง ๋ถ์กฑํ์ง ์๋ค๋ฉด ์ด๋ค ์์ async ํจ์๋ค๋ ๋์์ ์ผ์ ์ ์ง ๋ ์ ์๊ณ async ํจ์๊ฐ ์ผ์ ์ ์ง๋ ๋ ๋ค๋ฅธ ํจ์๋ค์ด ๋์ํ ์ ์์ต๋๋ค.
// example 3.9
run().catch((error) => console.error(error.stack));
async function run() {
// await ํ ๋๋ง๋ค run()์ด ์ผ์์ ์ง๋๊ธฐ ๋๋ฌธ์ ์๋ ์ฝ๋ฐฑ์ด ์ํ๋ฉ๋๋ค.
setImmediate(() => console.log("Hello, World!"));
// ๋ฃจํ๋ฅผ ๋ ๋ ๋ง๋ค, run() ํจ์๊ฐ ์ผ์์ ์ง ๋๊ณ ๋ค์ tick์ ์ฌ๊ฐ๋ฉ๋๋ค.
while (true) {
await new Promise((resolve) => setImmediate(resolve));
}
}
์ด ๋ฐฉ์์ ์ด์ฉํ๋ฉด ์ค๋ ์๊ฐ์ด ์์๋๋ ๋๊ธฐ ํจ์๋ค์ async ํจ์๋ค์ ํตํด ๋จ์ํ ํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๋งค์ฐ ํฐ ํผ๋ณด๋์น ์๋ฅผ ๊ณ์ฐํ๋ ํจ์ ๋ ๊ฐ๋ฅผ ๋ณ๋ ฌ๋ก ์คํํ๊ณ ์ ํ ๋, async/await ์ด ์๋ค๋ฉด ํธ๋ฒ์ ์ธ ์ฌ๊ท๋ฐฉ๋ฒ์ด ํ์ํ์ง๋ง async/await๋ ์ด ์ฒ๋ฆฌ๋ฅผ ํ๋ฒํ๊ฒ ๋ง๋ค์ด ๋ฒ๋ฆฝ๋๋ค.
// example 3.10
await Promise.all([fibonacci(50000), fibonacci(50000)]);
async function fibonacci(n) {
let [prev2, prev1, cur] = [1, 1, 1];
for (let i = 2; i < n; ++i) {
// ๋ค๋ฅธ ํธ์ถ์ด ์งํ๋ ์ ์๋๋ก fibonacci()๋ฅผ ์ผ์์ ์ง ์ํต๋๋ค
await new Promise((resolve) => setImmediate(resolve));
// "Fib: 10000"
// "Fib: 10000"
// "Fib: 20000" ...
if (i % 10000 === 0) console.log("Fib:", i);
cur = prev1 + prev2;
prev2 = prev1;
prev1 = cur;
}
return cur;
}
์ด ์๋ ๋จ์ํ์ง๋ง ์์ฐ์ค๋ฝ์ง๋ ์์ต๋๋ค. ์ข ๋ ํ์ค์ ์ธ ์ฌ๋ก๋ ํด๋ฌ์คํฐ๋ง ๊ฐ์ด ์ ์ฌ์ ์ผ๋ก ๋งค์ฐ ๋น์ผ ์๊ณ ๋ฆฌ์ฆ์ ์ํํ๋ Express API ์ฒ๋ฆฌ์
๋๋ค. ๋ณธ์ธ์ ์ด๋ฌํ ํจํด์ ์์ฉ Express API์์ ์ฌ์ฉํ ๊ฒฝํ์ด ์์ต๋๋ค. ๋ค๋ฅธ ๋ผ์ฐํธ๋ค์ ๋ด์ํ์ง ์๊ณ ํ ๋ผ์ฐํธ์์ O(n^5)
ํด๋ฌ์คํฐ๋ง ์๊ณ ๋ฆฌ์ฆ์ ์ํํ์ต๋๋ค.
์ฌ๊ธฐ์ ํต์ฌ์ ์ธ ์ฌํญ์ ์ฌ๋ฌ๋ถ์ด await
์ผ๋ก ์ผ์ ์ ์ง ์ํค๊ฑฐ๋ return
๋๋ throw
๋ฅผ ํตํด ํจ์๋ฅผ ์ข
๋ฃํ์ง ์๋๋ค๋ฉด async ํจ์๋ ์ด๋ค ๊ฐ์ญ ์์ด ์ฒ๋ฆฌ๋ ๊ฒ์ด๋ผ๋ ์ ์
๋๋ค. ์์์ ์ผ๋ก ์๋ฐ์คํฌ๋ฆฝํธ๋ ์ฌ์ ํ ๋จ์ผ ์ฐ๋ ๋์์ ์ํ๋๊ธฐ ๋๋ฌธ์ ๋ ๊ฐ์ ๋น๋๊ธฐ ํจ์๋ ๋์์ ๋์ํ ์ ์์ต๋๋ค. ํ์ง๋ง await
๋ฅผ ํตํด ์ฌ๋ฌ๋ถ์ async ํจ์๋ฅผ ์ผ์ ์ ์ง ์ํด์ผ๋ก์จ, ์ด๋ฒคํธ ๋ฃจํ๋ก ์ง์
ํ๊ฒ ํ์ฌ ๋ค๋ฅธ ํจ์๋ค์ด ์ํ๋ ๊ธฐํ๋ฅผ ๊ฐ์ง ์ ์๋๋ก ํ ์ ์์ต๋๋ค.
Async/Await vs Generators
async/await๋ generators
์ ๊ณตํต์ ์ด ๋ง์ต๋๋ค. generators๋ 2015๋
๋ํ ์๋ฐ์คํฌ๋ฆฝํธ ๊ท๊ฒฉ์ ํน์ง์
๋๋ค. ๋น๋๊ธฐ ํจ์์ ๊ฐ์ด, generator ํจ์๋ ์ผ์ ์ ์ง๋๊ณ ํ์ ์ฌ๊ฐ๋ ์ ์์ต๋๋ค. ๋ค๋ง, async ํจ์์ generators ํจ์ ์ฌ์ด์๋ ๋ ๊ฐ์ง ์ค์ํ ์ฐจ์ด์ ์ด ์์ต๋๋ค.
generator ํจ์๋ฅผ ์ผ์ ์ ์ง ์ํค๊ธฐ ์ํด์๋
await
์ด ์๋yield
ํค์๋๋ฅผ ์ฌ์ฉํฉ๋๋ค.generator ํจ์๋ฅผ ์ผ์ ์ ์ง ์ํค๋ฉด ์ ์ด๋ ์๋ฐ์คํฌ๋ฆฝํธ ์์ง(์ธํฐํ๋ฆฌํฐ)๋ก ๊ฐ๋ ๊ฒ์ด ์๋๋ผ ์ฌ๋ฌ๋ถ์ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๋ก ๋์๊ฐ๋๋ค. generator ๊ฐ์ฒด์
next()
๋ฅผ ํธ์ถํ์ฌ generator ํจ์๋ฅผ ์ฌ๊ฐํฉ๋๋ค.
yield
, next()
๋ฅผ ์ฌ์ฉํ์ฌ generator ํจ์๋ฅผ ์ผ์ ์ ์ง ์ํค๊ฑฐ๋ ์ฌ๊ฐํ๋ ์ฌ๋ก์
๋๋ค.
// example 3.11
// The `function*`ํํ์ผ๋ก ์ผ๋ฐํจ์๋ฅผ generator() ํจ์๋ก ๋ง๋ญ๋๋ค.
const generatorFunction = function* () {
console.log("Step 1");
yield 1;
console.log("Step 2");
yield 2;
console.log("Done");
};
// generator ํจ์์ ๋ฐํ๊ฐ์ generator ๊ฐ์ฒด์
๋๋ค.
// generator ํจ์๋ ์ฌ๋ฌ๋ถ์ด next()๋ฅผ ํธ์ถํ ๋ ์์ํฉ๋๋ค.
const generatorObject = generatorFunction();
let yielded = generatorObject.next(); // Prints "Step 1"
console.log(yielded.value); // Prints "1"
yielded = generatorObject.next(); // Prints "Step 2"
console.log(yielded.value); // Prints "2"
generatorObject.next(); // Prints "Done"
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ์ ํ์ฉํ๋ฉด generator ๋ async/await์ ์ฌ์ค์ ๋์ผํ ํจํด์ผ๋ก ์ด์ฉํ ์ ์์ต๋๋ค. ๊ฐ์ฅ ์ ์๋ ค์ง ๋์์ฑ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ 'co
'์
๋๋ค. ๋ค์์ async/await ๋์ ์ 'co'๋ฅผ ์ฌ์ฉํ๋ ์ฌ๋ก์
๋๋ค.
// example 3.12
const co = require("co");
// co.wrap()์ generator๋ฅผ async ํจ์์ฒ๋ผ ๋ง๋ค์ด ์ค๋๋ค.
const runCo = co.wrap(function* () {
// 1์ดํ 'Hello, World!'๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
yield new Promise((resolve) => setTimeout(() => resolve(), 1000));
console.log("Hello, World!");
});
// In particular, wrapped functions return a promise
runCo().catch((error) => console.log(error.stack));
Co๋ async/await๊ฐ ํ์์ ์ผ๋ก ์ง์ํ์ง ๋ชปํ๋ ๋ช ๊ฐ์ง ๊น๋ํ ํน์ง๋ค์ ์ ๊ณตํฉ๋๋ค. ์ฌ์ฉ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ผ๋ ๋๋ถ์, co๋ ์ข ๋ ํ์ฅ๋ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, co๋ ์ฌ๋ฌ๋ถ์ด ์ธ์ promise ๋ฐฐ์ด์ด๋ promise ๋งต์ yield
ํ ์ง ๋ค๋ฃฐ ์ ์์ต๋๋ค.
// example 3.13
const runCo = co.wrap(function* () {
const p1 = Promise.resolve("Hello");
const p2 = Promise.resolve("World");
// Co๋ promise ๋ฐฐ์ด์ด๋ promise ์์ฑ์ ๊ฐ๋ ๊ฐ์ฒด๋ค์ ๋ฐฐ์ด์ ๋ฐ๊ฟ ์ ์์ต๋๋ค.
// async/await ๋ผ๋ฉด, promise ๋ฐฐ์ด์ await์ ํ๊ธฐ ์ํด์๋
// Promise.all()์ ์ฌ์ฉํด์ผ๋ง ํ์ต๋๋ค.
console.log(yield [p1, p2]); // [ 'Hello', 'World' ]
console.log(yield { p1, p2 }); // { p1: 'Hello', p2: 'World' }
});
co์ ๋ฌต์์ promise ๋ณํ์ ๋จ์ ์ promise๋ก ๋ฐ๊ฟ ์ ์๋ ์ด๋ค ๊ฒ์ yield ํ ๋ error๊ฐ ๋ฐ์ํ๋ค๋ ์ ์ ๋๋ค.
// example 3.14
const runCo = co.wrap(function* () {
// 'TypeError: You may only yield a function, promise, generator,
// array, or object but the following object was passed: "1"'
yield 1;
});
์ค์ , co๊ฐ yield 1
์ ์ค๋ฅ๋ก ๋ค๋ฃฌ๋ค๋ ๊ฒ์ ์๋ง์ ์ค๋ฅ๋ค์ catchํ๋๋ฐ ๋์์ ์ค๋๋ค. ํ์ง๋ง ๋ง์ ๋ถํ์ํ ์ค๋ฅ๋ฅผ ์ผ๊ธฐํ๊ธฐ๋ ํฉ๋๋ค. async/await์์, await 1
์ ์ ์์ด๊ณ ๊ฐ 1๋ก ํ๊ฐํ๋ฉฐ ์ด๊ฒ์ด ์ข ๋ ๊ฒฌ๊ณ ํด ๋ณด์
๋๋ค.
Async/await๋ co, generator๋ฅผ ๋ฐ์ด๋๋ ๋ช ๊ฐ์ง ๋ค๋ฅธ ์ฅ์ ๋ค์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ๊ฐ์ฅ ํฐ ๊ฒ์async/await๋ node.js๋ฅผ ๋น๋กฏํด ํ ์๋์ ๋ธ๋ผ์ฐ์ ๋ค์ด ๊ธฐ๋ณธ์ผ๋ก ์ง์ํ๋ค๋ ์ ์
๋๋ค. ๊ทธ๋์ co ๊ฐ์ด ๋ณ๋์ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํ์ํ์ง๋ ์์ต๋๋ค. ๋ํ async/await๋ ํจ์ฌ ๊น๋ํ ์คํ ์ถ์ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. co์ ์คํ ์ถ์ ์ ์ค๋ฅ ํ์
์ ๋ชจํธํ๊ฒ ๋ง๋๋ ์๋ง์ generator.next()
์ onFulfilled
์ถ๋ ฅํฉ๋๋ค.
// example 3.15
const runCo = co.wrap(function* () {
yield new Promise((resolve) => setImmediate(resolve));
throw new Error("Oops!");
});
// Error: Oops!
// at /test.js:3:9
// at Generator.next (<anonymous>)
// at onFulfilled (/node_modules/co/index.js:65:19)
// at <anonymous>
runCo().catch((error) => console.log(error.stack));
๋น์ทํ ์ํฉ์์, async/await ์คํ ์ถ์ ์ ํจ์๋ช
์ ๋์ค์ง๋ง generator.next(), onFulfilled
๋ฑ์ ์ถ๋ ฅํ์ง ์์ต๋๋ค. Async/await์ onFulfilled์ ์ฌ์ฉ์ ๋ชจ๋๊ฐ ์๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ธํฐํ๋ฆฌํฐ ๋ชจ๋์์ ๋์ํ๊ธฐ ๋๋ฌธ์
๋๋ค.
// example 3.16
async function runAsync() {
await new Promise((resolve) => setImmediate(resolve));
throw new Error("Oops!");
}
// Error: Oops!
// at runAsync (/home/val/test.js:5:9)
// at <anonymous>
runAsync().catch((error) => console.log(error.stack));
์ผ๋ฐ์ ์ผ๋ก, async/await๋ ์๋ฐ์คํฌ๋ฆฝํธ ๋ด๋ถ์์ ๊ธฐ๋ณธ ์ง์๋๊ณ , ๋ถํ์ํ ์ค๋ฅ ๋ค์ ์ ๊ฒ ์ผ์ผํค๋ฉฐ ์ฌ๋ฌ๋ถ์ด ํ์๋ก ํ๋ ๋๋ถ๋ถ์ ๊ธฐ๋ฅ์ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์ ๋ ๋์ ๋ฐฉ๋ฒ์ ๋๋ค. Co๋ ๋ช ๊ฐ์ง ๋ฌธ๋ฒ์ ์ผ๋ก ๊น๋ํ ํธ์ด์ฑ์ ์ ๊ณตํ๊ณ ๊ตฌํ ๋ธ๋ผ์ฐ์ ์์๋ ๋์ํ์ง๋ง, ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ์ ์ ๋นํ ํ ๋งํผ ์ถฉ๋ถํ์ง๋ ์์ต๋๋ค.
Core Principles: ํต์ฌ ์๋ฆฌ
์ง๊ธ๊น์ง async ํจ์๊ฐ ์ผ์ ์ ์ง ํ๋ค๋ ๊ฒ์ด ์ด๋ค ์๋ฏธ ์ธ์ง์ ๋ํด ์์ธํ ๋ค๋ฃจ์์ต๋๋ค. ๊ทธ๋ ๋ค๋ฉด, ๊ฐ๋ฐ์๊ฐ ์์ ์ ์ฑ์ async/await๋ฅผ ์ฌ์ฉํ๋ค๋ ๊ฒ์ ๋ฌด์์ ์๋ฏธํ๋ ๊ฒ์ผ๊น์?
promise๊ฐ ๋ ์ ์๋ ๊ฐ์ await
ํ์ง ๋ง์ธ์.
await
ํ์ง ๋ง์ธ์.await 1
์ด ๊ฐ๋ฅํ๋ค๊ณ ๊ทธ๋ ๊ฒ ํด์ผ๋ง ํ๋ ๊ฒ์ ์๋๋๋ค. ๋ง์ async/await์ ์ด๋ณด์๋ค์ await์ ์ค์ฉํ๊ฑฐ๋ ๋จ์ฉํ๊ณค ํฉ๋๋ค.
// example 3.17
async function findSubstr(arr, str) {
// Don't do this! There's no reason for this function to be async
// ์ด๋ฐ๊ฑฐ ํ์ง ๋ง์ธ์. ์ด ํจ์๊ฐ ๋น๋๊ธฐ ํจ์์ฌ์ผํ ์ด์ ๊ฐ ์์ต๋๋ค.
for (let i = await 0; i < arr.length; ++i) {
if (await arr[i].includes(str)) return arr[i];
}
}
์ผ๋ฐ์ ์ผ๋ก, promise๊ฐ ๋ ๊ฒ์ผ๋ก ๊ธฐ๋๋๋ ๊ฐ์ ๋ํด์ await
์ ์ฌ์ฉํ์ธ์. ๊ฒฐ์ฝ promise๊ฐ ๋ ์ ์๊ฑฐ๋, promise ์ผ ์๋ ์๋ค๊ณ ๊ฑฐ์ง์ผ๋ก ์์ํ๋ ๊ฐ์๋ await
์ ํ ์ด์ ๋ ์์ต๋๋ค.
findSubstr()
ํจ์๋ฅผ async๋ก ๋ง๋๋ ์ ์ผํ ์ด์ ๋ ์คํ์ ์ผ์ ์ ์ง ์์ผ์ ๋ค๋ฅธ ํจ์๋ค๋ก ํ์ฌ๊ธ example 3.10 ์ฒ๋ผ ์ํํ๋๋ก ํ ๋์
๋๋ค. ์ด๊ฒ์ findSubstr()
๊ฐ ๋๋์ ๋ฐฐ์ด์ ์ฒ๋ฆฌํ๋ค๊ณ ํ ๋๋ ์ ์ฉํ ๊ฒ์
๋๋ค. ์ด ๊ฒฝ์ฐ, ๋ค๋ฅธ ์์
๋ค์ด ์ฒ๋ฆฌ๋ ๊ธฐํ๋ฅผ ๊ฐ๋๋ก ํ๊ธฐ ์ํด await new Promise(setImmediate)
๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
await์ ์ํ๋ ์ด๋ค ๊ฐ๋ค๋ ์ผ๋จ, promise๋ก ๋ฐ๊ฟ ๋์์ผ๋ง ํฉ๋๋ค. ์๋ค ๋ค์ด, ๋ณ๋ ฌ๋ก ๋ณต์์ promise๋ค์ awaitํ๊ธฐ ์ํด์๋ Promise.all()์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
// example 3.18
async function run() {
const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
// 'arr1'์ array์ด์ง promise๊ฐ ์๋๋๋ค. ๋ฐ๋ผ์ ๋์ํ์ง ์์ต๋.
const arr1 = await [p1, p2];
// arr1์ ๋ฐฐ์ด์ด๊ธฐ ๋๋ฌธ์ promise๋ฅผ ๋ฐํํ๋ ๋์ฐ๋ฏธ ํจ์ Promise.all์ ์ฌ์ฉํด์ผ ํ๋ค.
const arr2 = await Promise.all(arr1);
}
Promise๊ฐ ์๋๋ฉด ๊ทธ๋ฅ return
์ ์ฌ์ฉํ์ธ์.
return
์ ์ฌ์ฉํ์ธ์.example 3.4์์ ๋ณด๋ฏ์ด, async ํจ์๋ promise๋ฅผ ๋ฐํํ ์ ์์ต๋๋ค. ํ์ง๋ง ๊ทธ๋ ๊ฒ ํ๋ฉด ๋ค์ ๋ปํ์ง ๋ชปํ ์ํฉ์ ๋ง์ต๋๋ค. ํด๊ฒฐ๋ ๊ฐ์ผ๋ก promise๋ฅผ ์ฌ์ฉํ๋ ๋์ ์ ๊ฐ์ผ๋ก ํด๊ฒฐ๋๋๋ก await์ ์ฌ์ฉํ๊ณ ๊ทธ๋ฆฌ๊ณ ๋์ ๊ทธ ๊ฒฐ๊ณผ๊ฐ(ํด๊ฒฐ๊ฐ)์ ๋ฐํํ๋๋ก ํ๋ ๊ฒ์ด ์ข์ต๋๋ค. async์ return ์ฌ์ด์ ์ฐจ์ด๋ฅผ ํํํ๊ธฐ ๋ณด๋ค๋ await๋ฅผ ์ฌ์ฉํ๊ณ ๋์ ์ ์ฐฉ๋ ๊ฐ์ ๋ฐํํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ผ๋ก ๋ ์ฝ์ต๋๋ค.
// example 3.19
async function fn1() {
// ๊ด์ฐฎ์ง๋ง, example 3.4์์ ๋ณด์๋ฏ์ด try/catch ์ฌ์ฉ์ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ์ง ๋ชปํ๋
// ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
return asyncFunction();
}
async function fn2() {
// ๋ช ์ค ๋ ๋ค์ด๊ฐ๊ธด ํ์ง๋ง ๋ฌธ์ ์์ง๊ฐ ์ ์ต๋๋ค. ์ด ํจ์ ๋ด๋ถ์์
// asyncFunction()์ ์ค๋ฅ๋ค์ ์ฒ๋ฆฌํ๊ณ ์ ํ๋ค๋ฉด ์ด ๋ฐฉ๋ฒ์ด ์ข๋ค.
const ret = await asyncFunction();
return ret;
}
forEach(), map()
๊ฐ์ ๋ฐฐ์ด ๋์ฐ๋ฏธ ํจ์์๋ await
์ฌ์ฉ๋ณด๋ค loop ๋ฅผ ์ฌ์ฉํ์ธ์.
forEach(), map()
๊ฐ์ ๋ฐฐ์ด ๋์ฐ๋ฏธ ํจ์์๋ await
์ฌ์ฉ๋ณด๋ค loop ๋ฅผ ์ฌ์ฉํ์ธ์.async ํจ์ ๋ด๋ถ์์๋ง await์ ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์, forEach() ๊ฐ์ ํจ์ํ ๋ฐฐ์ด ํจ์์์ async ํจ์๋ค์ sync ํจ์๋ค๊ณผ๋ ๋ค๋ฅธ ํํ๋ฅผ ๋ณด์ ๋๋ค.
// example 3.20
async function test() {
const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
// SyntaxError: Unexpected identifier
[p1, p2].forEach(p => { await p; });
}
ํ์ํ ๊ฒ์ด๋ผ ๊ณค async ํ์ดํ ํจ์๋ผ๊ณ ์๊ฐํ ์ง ๋ชจ๋ฅด์ง๋ง, await
์ ํด๋ test()
๋ ์ผ์ ์ ์งํ์ง ์์ต๋๋ค.
// example 3.21
async function test() {
const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
// ๋ฐฐ์ด ๊ฐ์ ๋งํผ, 2๊ฐ์ async ํจ์๋ฅผ ์ค๋นํ์ง๋ง test()๋ฅผ ์ผ์ ์ ์ง์ํค์ง๋ ์์ต๋๋ค.
// await p๋ก ์ ์ง๋๋ ๊ฒ์ test()๊ฐ ์๋ ํ์ดํ ํจ์์
๋๋ค.
[p1, p2].forEach(async (p) => {
console.log(await p);
});
// '1', '2' ๋ณด๋ค ๋จผ์ 'Done'์ด ์ถ๋ ฅ๋ฉ๋๋ค. ์๋ดํ๋ฉด await p๋ test()๊ฐ ์๋
// ํ์ดํ ํจ์๋ฅผ ์ผ์์ ์ง ์ํค๊ธฐ ๋๋ฌธ์
๋๋ค.
console.log("Done");
}
์ค๋ฅ๋ .catch()
๋ก ์ฒ๋ฆฌํ์ธ์.
.catch()
๋ก ์ฒ๋ฆฌํ์ธ์.ํตํฉ๋ ์ค๋ฅ ๊ด๋ฆฌ๋ async/await์ ๊ฐ์ฅ ๊ฐ๋ ฅํ ํน์ง๋ค ์ค ํ๋ ์
๋๋ค. asyncFn().catch()
๋ asyncFn()
ํจ์ ๋ด๋ถ์์ ๋ฐ์ํ๋ ๋ชจ๋ ์ค๋ฅ ๋ค(๋๊ธฐ ๋๋ ๋น๋๊ธฐ ์ค๋ฅ)์ ์ฒ๋ฆฌํฉ๋๋ค. example 3.4: try/catch
๋ p
๊ฐ ์คํจ๋ฉด return p
๋ก ๋ฐ์ํ๋ ์ค๋ฅ ๋ค์ ์ฒ๋ฆฌํ์ง ๋ชปํ๋ ๊ฒ์ ๊ธฐ์ตํ๊ธฐ ๋ฐ๋๋๋ค.
// example 3.22
async function fn1() {
// p ๊ฐ rejeced ์ผ ๋, return p๋ก ๊ทธ ์ค๋ฅ๋ฅผ ์ก์ง ๋ชปํฉ๋๋ค.
try {
/* Complex logic */
} catch (err) {
handleError(err);
}
}
async function fn2() {
/* Complex logic */
}
// ์์ฃผ ์ข์ต๋๋ค~~
fn2().catch(handleError);
์ผ๋ฐ์ ์ผ๋ก, async ํจ์์์ ๋ฐ์ํ๋ ๋๋ถ๋ถ์ ์ค๋ฅ๋ .catch()
์์ ์ก์ ์ ์์ต๋๋ค. .catch()
๊ฐ ์๋ async/await ์ฝ๋๋ฅผ ๋ณด๊ฒ ๋๋ค๋ฉด ์ด๋๊ฐ ์ฒ๋ฆฌ๋์ง ๋ชปํ ์ค๋ฅ๊ฐ ์กด์ฌํ๊ฒ ๋๋ค๋ ๊ฒ์ ๋ช
์ฌํ์ธ์. ์ข์ async/await ์ฝ๋๋ ๋ชจ๋ async ํจ์ ํธ์ถ์ด .catch()
๋ก ์กํ ์ ์๋๋ก ํ๋ wrap()
ํจ์ ๊ฐ์ด ์ง์คํ๋ ๊ธฐ๋ฒ์ ์ฌ์ฉํฉ๋๋ค.
// example 3.23
const wrap = (fn) =>
function () {
// ํจ์ ํธ์ถ์ด ์ค๋ฅ ์ฒ๋ฆฌ๊ธฐ๋ฅผ ๊ฐ๋๋ก ๋ณด์ฅํฉ๋๋ค.
return fn.apply(null, arguments).catch((error) => console.log(error));
};
const [fn1, fn2] = [
async function () {
throw Error("err1");
},
async function () {
throw Error("err2");
},
].map(wrap);
fn1(); // Prints "err1"
fn2(); // Prints "err2"
Exercise 1: Implementing Custom Thenables
๋ง์ถคํ thenable์ ๊ตฌํํด ๋ด ์๋ค.
Example 3.2์์ ๋ณด์๋ฏ์ด, ์ด๋ค ๊ฐ์ฒด๋ฅผ async/await์ ์ฎ๊ธฐ ์ํด ํ์ํ ๊ฒ์ then()
ํจ์์
๋๋ค. await ๋ ๋ด๋ถ์ ์ผ๋ก then()
์ ํธ์ถํ๊ณ onFulfilled()
๋๋ onRejected()
๊ฐ ํธ์ถ๋ ๋๊น์ง ํ์ฌ async ํจ์๋ฅผ ์ผ์ ์ ์ง ์ํต๋๋ค. ์ด๊ฒ์ ์ฌ๋ฌ๋ถ์ด ์ด๋ค ๊ฐ์ฒด๋ผ๋ then()
ํจ์๋ฅผ ์ถ๊ฐํจ์ผ๋ก์จ ๊ทธ ๊ฐ์ฒด๊ฐ async/await์ ์ํธ ์๋ ํ๋๋ก ๋ง๋ค ์ ์๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
superagent ๊ฐ์ ๋ง์ ์๋ฐ์คํฌ๋ฆฝํธ HTTP ๋ชจ๋๋ค์ ์ฌ๋ฌ ํจ์๋ค๋ก request๋ค์ ์ฒ๋ฆฌํด ๋๊ฐ๋๋ก chainable API๋ฅผ ์ ๊ณตํฉ๋๋ค.
superagent.get(url).set('API-Key', 'test').end((err, res) => { /* Handle response */ });
์๋ HTTPRequests ํด๋์ค๋ chainable API๋ฅผ ๊ฐ์ง ๋จ์ํ๋ HTTP ๋ชจ๋์ ์ ๊ณตํฉ๋๋ค. ํ์ง๋ง ํ์ฌ๋ exec()
ํจ์๋ฅผ ๊ฒฝ์ ํ๋ ์ฝ๋ฐฑ๋ค ๋ง ์ง์ํฉ๋๋ค. then()
ํจ์๋ฅผ ๊ตฌํํจ์ผ๋ก์จ ์ด HTTPRequests ํด๋์ค๊ฐ async/await์ ์๋ํ๋๋ก ํด๋ณด์ธ์.
์๋๋ ์ด๊ธฐ ์ฝ๋์ ๋๋ค. ์ด ์ฝ๋๋ฅผ ๋ณต์ฌํด์ node.js๋ก ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด ๋ณด์ธ์. ๋๋ ์ฌ๋ฌ๋ถ์ ๋ธ๋ผ์ฐ์ ๋ก codepen ์ฌ์ดํธ(http://bit.ly/async-await-exercise-31)์ ์ ์ํด์ ์์ฑํด๋ณผ ์๋ ์์ต๋๋ค.
class HTTPRequest {
// ์ค์ง ์๋ then() ๋ง ์์ ํ์ธ์.
static create() {
return new HTTPRequest();
}
get(url) {
this.method = "get";
this.url = url;
return this;
}
exec(callback) {
fetch(this.url, this)
.then((res) => res.json())
.then((res) => callback(null, res))
.catch(callback);
}
then(onFulfilled, onRejected) {
throw new Error("Not Implemented"); // Implement this function
}
}
// Don't modify the below code
run().catch((error) => console.error(error.stack));
async function run() {
const url =
"https://" + "us-central1-mastering-async-await.cloudfunctions.net/posts";
const res = await HTTPRequest.create().get(url);
console.log("Success", res[0].id === 51);
}
Exercise 2: Async forEach()
Example 3.21 ๊ฐ์ด, forEach ๋ฐฐ์ด ํจ์๋ async/await ์ฌ์ฉ ์ ๋ช ๊ฐ์ง ๋ณ๋ ์ํฉ์ด ๋ฐ์ํฉ๋.
async function fn1() {
// SyntaxError: await p๋ async ํจ์ fn1์ ์์ง ์์ต๋๋ค
[1, 2].forEach(p => {
await p;
});
}
async function fn2() {
[Promise.resolve(1), Promise.resolve(2)].forEach(async (p) => {
console.log(await p);
});
// '1' & '2'์ ์์ 'Done'์ด ์ถ๋ ฅ๋ฉ๋๋ค. ์๋ํ๋ฉด,
// ์ await์ ํ์ดํ ํจ์๋ฅผ ์ผ์์ ์ง ์ํต๋๋ค. fn2()๊ฐ ์๋๋๋ค!
console.log('Done');
}
๋ฐฐ์ด๊ณผ async ํจ์๋ฅผ ์ธ์๋ก ๊ฐ๋ forEachAsync()
ํจ์๋ฅผ ๊ตฌํํ์ธ์.
๋ฐฐ์ด์ ์์๋ค์ ๋ํด ์์ฐจ์ ์ผ๋ก fn()
์ ํธ์ถํฉ๋๋ค. forEachAsync()
๋ ๋ค์ ์์๋ฅผ ์ด์ด๊ฐ๊ธฐ ์ ์ ํ์ฌ ์์์ fn()
์ ๊ธฐ๋ค๋ ค์ผ ํฉ๋๋ค.
์๋๋ ์ด๊ธฐ ์ฝ๋์ ๋๋ค. node.js๋ก ์ด๋ฒ ์์ ๋ฅผ ์ฒ๋ฆฌํ๊ฑฐ๋ ์ฌ๋ฌ๋ถ์ ๋ธ๋ผ์ฐ์ ๋ก codepen ์ฌ์ดํธ(http://bit.ly/async-await-exercise-32)์ ์ ์ํด์ ์์ฑํด๋ณผ ์๋ ์์ต๋๋ค.
// ๋ค์ ํจ์๋ฅผ ๊ตฌํํ์ธ์.
async function forEachAsync(arr, fn) {
throw Error("Not Implemented!");
}
// Below is test code, don't modify this
run().catch((err) => console.log(err.stack));
async function run() {
let i = 0;
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
async function fn1(n) {
await new Promise((resolve) => setTimeout(resolve, 100 - n * 10));
if (i++ !== n) throw Error("Make sure to `await` on `fn()`");
}
await forEachAsync(arr, fn1);
if (i !== 10) throw Error("Call `fn()` on every array element");
console.log("Success!");
}
Last updated
Was this helpful?