Language/JavaScript

๐Ÿ”„ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ด๋ฒคํŠธ ๋ฃจํ”„ ๋™์ž‘ ๊ตฌ์กฐ & ์›๋ฆฌ ๋ํŒ์™•

์ธํŒŒ_ 2023. 5. 8. 13:30

js-event-loop

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋น„๋™๊ธฐ์™€ ์ด๋ฒคํŠธ ๋ฃจํ”„

 

๋ธŒ๋ผ์šฐ์ €์˜ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ๋กœ ์ž‘์—…์„ ๋™์‹œ์—

Javascript๋Š” ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ์–ธ์–ด๋ผ๊ณ  ๋“ค์–ด๋ณธ ์ ์ด ์žˆ์„ ๊ฒƒ์ด๋‹ค. '์‹ฑ๊ธ€' ์Šค๋ ˆ๋“œ๋ผ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ์ž‘์—…๋งŒ ์ˆ˜ํ–‰์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ๋ฐ˜๋ฉด Java ๋‚˜ Python์€ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ๋ฅผ ์ง€์›ํ•˜์—ฌ ์›ํ•˜๋Š” ์ฝ”๋“œ ๋กœ์ง์„ ๋™์‹œ์— ์ˆ˜ํ–‰ ์‹œํ‚ค๋Š” ๋ฉ€ํ‹ฐ ์ž‘์—…์ด ๊ฐ€๋Šฅํ•˜๋‹ค. 

๊ทธ๋Ÿฐ๋ฐ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด๋‚˜ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ, ํƒ€์ด๋จธ์™€ ๊ฐ™์€ ์ž‘์—…์„ ๋ฉ€ํ‹ฐ๋กœ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค. ๋งŒ์ผ ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ๋กœ ๋ธŒ๋ผ์šฐ์ € ๋™์ž‘์ด ํ•œ๋ฒˆ์— ํ•˜๋‚˜์”ฉ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋˜๋ฉด, ์šฐ๋ฆฌ๊ฐ€ ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์„ ๋™์•ˆ ๋ธŒ๋ผ์šฐ์ €๋Š” ํŒŒ์ผ์„ ๋‹ค ๋ฐ›์„ ๋•Œ๊นŒ์ง€ ์›น์„œํ•‘๋„ ๋ชปํ•˜๊ณ  ๋ฉˆ์ถฐ ๋Œ€๊ธฐํ•ด์•ผ ํ•  ๊ฒƒ์ด๋‹ค. ๋”ฐ๋ผ์„œ ํŒŒ์ผ ๋‹ค์šด, ๋„คํŠธ์›Œํฌ ์š”์ฒญ, ํƒ€์ด๋จธ, ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ด๋Ÿฌํ•œ ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๊ณ  ๋ฐ˜๋ณต์ ์ธ ์ž‘์—…๋“ค์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์ด ์•„๋‹Œ ๋ธŒ๋ผ์šฐ์ € ๋‚ด๋ถ€์˜ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ์ธ Web APIs์—์„œ ๋น„๋™๊ธฐ + ๋…ผ๋ธ”๋กœํ‚น์œผ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค. ๋น„๋™๊ธฐ + ๋…ผ๋ธ”๋กœํ‚น(Async + Non blocking)๋Š” ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๊ฐ€ ์ž‘์—…์„ ๋‹ค๋ฅธ ๊ณณ์— ์š”์ฒญํ•˜์—ฌ ๋Œ€์‹  ์‹คํ–‰ํ•˜๊ณ , ๊ทธ ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ์ด๋ฒคํŠธ๋‚˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ๋ฐ›์•„ ๊ฒฐ๊ณผ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ์‹์„ ๋งํ•œ๋‹ค. (์‰ฝ๊ฒŒ ๋งํ•ด ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ์š”์ฒญ ์ž‘์—…์„ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์œผ๋กœ ์ „์ดํ•˜์—ฌ ๋™์‹œ์— ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•œ ๊ฒƒ์œผ๋กœ ์ดํ•ดํ•˜๋ฉด ๋œ๋‹ค)

์ฆ‰, ๋น„๋™๊ธฐ๋กœ ๋™์ž‘ํ•˜๋Š” ํ•ต์‹ฌ์š”์†Œ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์–ธ์–ด๊ฐ€ ์•„๋‹ˆ๋ผ ๋ธŒ๋ผ์šฐ์ €๋ผ๋Š” ์†Œํ”„ํŠธ์›จ์–ด๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ๋ณด๋ฉด ๋œ๋‹ค. Node.js ์—์„œ๋Š” libuv ๋‚ด์žฅ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ฒ˜๋ฆฌํ•œ๋‹ค.

 

์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” ๋ธŒ๋ผ์šฐ์ € ๋™์ž‘์„ ์ œ์–ดํ•˜๋Š” ๊ด€๋ฆฌ์ž

์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ์ธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์ž‘์—…์„ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ๋กœ ๋Œ๋ ค ์ž‘์—…์„ ๋™์‹œ์— ์ฒ˜๋ฆฌ์‹œํ‚ค๊ฒŒ ํ•˜๋˜๊ฐ€, ๋˜๋Š” ์—ฌ๋Ÿฌ ์ž‘์—… ์ค‘ ์–ด๋–ค ์ž‘์—…์„ ์šฐ์„ ์œผ๋กœ ๋™์ž‘์‹œํ‚ฌ ๊ฒƒ์ธ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ์„ธ์‹ฌํ•œ ์ปจํŠธ๋กค์„ ํ•˜๊ธฐ ์œ„ํ•ด ์กด์žฌํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ ์ด๋ฒคํŠธ ๋ฃจํ”„(Event Loop) ์ด๋‹ค. ์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” ๋ธŒ๋ผ์šฐ์ € ๋‚ด๋ถ€์˜ Call Stack, Callback Queue, Web APIs ๋“ฑ์˜ ์š”์†Œ๋“ค์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋ฉด์„œ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰๋˜๋Š” ์ž‘์—…๋“ค์„ ๊ด€๋ฆฌํ•˜๊ณ , ์ด๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ์ฒ˜๋ฆฌํ•˜์—ฌ ํ”„๋กœ๊ทธ๋žจ์˜ ์‹คํ–‰ ํ๋ฆ„์„ ์ œ์–ดํ•˜๋Š” ๋…€์„์ด๋‹ค. ๊ฐ„๋‹จํžˆ ํ‘œํ˜„ํ•˜์ž๋ฉด ๋ธŒ๋ผ์šฐ์ €์˜ ๋™์ž‘ ํƒ€์ด๋ฐ์„ ์ œ์–ดํ•˜๋Š” ๊ด€๋ฆฌ์ž๋ผ๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.

์ด๋ฒคํŠธ ๋ฃจํ”„์˜ ๋™์ž‘ ๊ณผ์ •์„ ๊ฐ„๋‹จํžˆ ์‚ดํŽด๋ณด์ž๋ฉด, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ setTimeout์ด๋‚˜ fetch ์™€ ๊ฐ™์€ ๋น„๋™๊ธฐ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ๋ธŒ๋ผ์šฐ์ € Web APIs์—๊ฒŒ ๋งก๊ธฐ๊ณ , ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์ด ๋๋‚œ ๊ฒฐ๊ณผ๋ฅผ ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ํ˜•ํƒœ๋กœ ํ(Callback Queue)์— ๋„ฃ๊ณ  ์ฒ˜๋ฆฌ ์ค€๋น„๊ฐ€ ๋˜๋ฉด ํ˜ธ์ถœ ์Šคํƒ(Call Stack)์— ๋„ฃ์–ด ๋งˆ๋ฌด๋ฆฌ ์ž‘์—…์„ ์ง„ํ–‰ํ•œ๋‹ค.

js-event-loop
๋งˆ์น˜ ์ˆœํšŒ(loop) ํ•˜๋Š”๋“ฏํ•˜์—ฌ ์ด๋ฒคํŠธ ๋ฃจํ”„๋ผ ๋ถ€๋ฅด๋Š” ๊ฒƒ์ด๋‹ค

์ด๋Ÿฌํ•œ ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ์ด์šฉํ•œ ํ”„๋กœ๊ทธ๋žจ ๋ฐฉ์‹์„ ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜(Event Driven) ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋ผ๊ณ  ํ•œ๋‹ค. ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ํ”„๋กœ๊ทธ๋žจ์˜ ํ๋ฆ„์ด ์ด๋ฒคํŠธ์— ์˜ํ•ด ๊ฒฐ์ •๋˜๋Š” ๋ฐฉ์‹์ด๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์‚ฌ์šฉ์ž์˜ ํด๋ฆญ์ด๋‚˜ ํ‚ค๋ณด๋“œ ์ž…๋ ฅ๊ณผ ๊ฐ™์€ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ๊ทธ์— ๋งž๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰ํ•œ๋‹ค. ๋Œ€ํ‘œ์ ์œผ๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ addEventListener(์ด๋ฒคํŠธ๋ช…, ์ฝœ๋ฐฑํ•จ์ˆ˜) ๊ฐ€ ์žˆ๊ฒ ๋‹ค.

์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ์œผ๋กœ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ณ , ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ์–ธ์–ด์— ๋น„ํ•ด ๋‹จ์ˆœํ•˜๊ณ  ์ง๊ด€์ ์ธ ์ฝ”๋“œ ์ž‘์„ฑ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋ฉฐ, ๋ธŒ๋ผ์šฐ์ €์™€ ๊ฐ™์€ ํ™˜๊ฒฝ์—์„œ๋„ ์•ˆ์ •์ ์ธ ์‹คํ–‰์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜์—ฌ ์‚ฌ์šฉ์ž์™€์˜ ์ƒํ˜ธ์ž‘์šฉ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๋ฅผ ์ดํ•ดํ•˜๊ณ  ์ ์ ˆํ•œ ๋ฐฉ์‹์œผ๋กœ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์€, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ด์šฉํ•œ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์— ์žˆ์–ด์„œ ๋งค์šฐ ์ค‘์š”ํ•˜๋‹ค.

๐Ÿ’ก ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์™œ ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ์ธ๊ฐ€?

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” 1995๋…„์— ๋„ท์Šค์ผ€์ดํ”„์—์„œ ์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋™์ ์ธ ์›น ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ๊ฐœ๋ฐœ๋œ ์Šคํฌ๋ฆฝํŠธ ์–ธ์–ด์ด๋‹ค. ๋‹น์‹œ์—๋Š” ๋ฉ€ํ‹ฐ ์ฝ”์–ด ํ”„๋กœ์„ธ์„œ๊ฐ€ ๋ณดํŽธํ™”๋˜์ง€ ์•Š์•˜๊ณ , ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ฐ„๋‹จํ•œ ์Šคํฌ๋ฆฝํŠธ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ์ฃผ๋กœ ์‚ฌ์šฉ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ณต์žกํ•œ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๋ฅผ ํ•„์š”๋กœ ํ•˜์ง€ ์•Š์•„, ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ์ ๊ณ , ๋™๊ธฐํ™” ๋ฌธ์ œ๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ๋Š” ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ๋กœ ๊ตฌํ˜„ํ•˜์˜€๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ๋Š” ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ์ž‘์—…์ด ์‹คํ–‰๋˜๋ฉด ๋‹ค๋ฅธ ์ž‘์—…๋“ค์ด ๋Œ€๊ธฐํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์‘๋‹ต์„ฑ์ด ๋–จ์–ด์ง„๋‹ค. ๋˜ํ•œ CPU ์ฝ”์–ด๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์„ฑ๋Šฅ์ด ์ œํ•œ๋œ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋“ค์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์–ธ์–ด ์ž์ฒด์˜ ์„ค๊ณ„๋ฅผ ๋ฐ”๊พธ๋Š” ๊ฒƒ ๋ณด๋‹จ, ๋ธŒ๋ผ์šฐ์ €์˜ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ๋ฅผ ์ด์šฉํ•˜๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์ง€์›ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํ•ต์‹ฌ์ด ์ด๋ฒคํŠธ ๋ฃจํ”„์ธ ๊ฒƒ์ด๋‹ค. (๋‹ค๋งŒ Web worker ์ตœ์‹  ๊ธฐ์ˆ ์„ ํ†ตํ•ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋„ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ•ด์กŒ๋‹ค)

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„ ๊ตฌ๋™ ํ™˜๊ฒฝ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ์†Œํ”„ํŠธ์›จ์–ด๋กœ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ž˜ ์•Œ๊ณ  ์žˆ๋Š” ์›น๋ธŒ๋ผ์šฐ์ €์™€ ๋Ÿฐํƒ€์ž„์ธ Node.js ๊ฐ€ ์žˆ๋‹ค. ์ด๋ฒคํŠธ ๋ฃจํ”„ ๋™์ž‘ ์›๋ฆฌ๋ฅผ ๋ฐฐ์šฐ๊ธฐ ์•ž์„œ, ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ์ธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์ด ์–ด๋Š ๊ณณ์„ ๊ฑฐ์ณ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š”์ง€ ์šฐ์„  ์ด ๋‘˜์˜ ๋‚ด๋ถ€ ๊ตฌ์„ฑ๋„๋ฅผ ๋ˆˆ์— ์ตํ˜€๋ณด์ž. 

๋ณธ ํฌ์ŠคํŒ…์—์„œ ์˜ˆ์‹œ๋ฅผ ๋“œ๋Š” ์›น๋ธŒ๋ผ์šฐ์ €๋Š” Chrome ๋ธŒ๋ผ์šฐ์ €์ด๋‹ค. ๋‹ค๋ฅธ ๋ธŒ๋ผ์šฐ์ €๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์ด๋‚˜ ๋‚ด๋ถ€ ๊ตฌ์„ฑ์ด ์•ฝ๊ฐ„์‹ ๋‹ค๋ฅผ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์€ ์œ ์˜ํ•˜์ž

 

๋ธŒ๋ผ์šฐ์ €์˜ ๋‚ด๋ถ€ ๊ตฌ์„ฑ๋„

๋ธŒ๋ผ์šฐ์ €๋Š” ์›น ์‚ฌ์ดํŠธ๋ฅผ ํ™”๋ฉด์— ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์—ญํ• ์„ ํ•˜๋Š” ๋ถ€ํ’ˆ๋“ค๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋‹ค. ๊ทธ์ค‘ ์šฐ๋ฆฌ๊ฐ€ ์•Œ์•„๋ณผ ๊ฒƒ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋น„๋™๊ธฐ ์ฝ”๋“œ์˜ ๋™์ž‘ ๊ณผ์ •์ด๋‹ˆ, ์ด์— ๊ด€๋ จ๋œ ๊ตฌ์„ฑ ์š”์†Œ๋กœ๋Š” Web APIs, Event Table, Callback Queue, Event Loop ๋“ฑ์ด ์žˆ๋‹ค.

์ด๋ฒคํŠธ๋ฃจํ”„

  • Call Stack : ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์ด ์ฝ”๋“œ ์‹คํ–‰์„ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ๊ตฌ์กฐ
  • Heap : ๋™์ ์œผ๋กœ ์ƒ์„ฑ๋œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด๊ฐ€ ์ €์žฅ๋˜๋Š” ๊ณต๊ฐ„
  • Web APIs: ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ œ๊ณตํ•˜๋Š” API ๋ชจ์Œ์œผ๋กœ, ๋น„๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰๋˜๋Š” ์ž‘์—…๋“ค์„ ์ „๋‹ดํ•˜์—ฌ ์ฒ˜๋ฆฌํ•œ๋‹ค. (AJAX ํ˜ธ์ถœ, ํƒ€์ด๋จธ ํ•จ์ˆ˜, DOM ์กฐ์ž‘ ๋“ฑ)
  • Callback Queue : ๋น„๋™๊ธฐ์  ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ์‹คํ–‰๋˜๋Š” ํ•จ์ˆ˜๋“ค์ด ๋Œ€๊ธฐํ•˜๋Š” ๊ณต๊ฐ„
  • Event Loop : ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋“ค์„ ์ ์ ˆํ•œ ์‹œ์ ์— ์‹คํ–‰์‹œํ‚ค๋Š” ๊ด€๋ฆฌ์ž
  • Event Table: ํŠน์ • ์ด๋ฒคํŠธ(timeout, click, mouse ๋“ฑ)๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์–ด๋–ค callback ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜์•ผ ํ•˜๋Š”์ง€๋ฅผ ์•Œ๊ณ  ์žˆ๋Š” ์ž๋ฃŒ๊ตฌ์กฐ (์œ„ ๊ทธ๋ฆผ์—๋Š” ์—†์Œ)

 

Web APIs์˜ ์ข…๋ฅ˜

Web APIs๋Š” ํƒ€์ด๋จธ, ๋„คํŠธ์›Œํฌ ์š”์ฒญ, ํŒŒ์ผ ์ž…์ถœ๋ ฅ, ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋“ฑ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ œ๊ณตํ•˜๋Š” ๋‹ค์–‘ํ•œ API๋ฅผ ํฌ๊ด„ํ•˜๋Š” ์ด์นญ์ด๋‹ค. Web API๋Š” ๋ธŒ๋ผ์šฐ์ €(Chrome)์—์„œ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋ธŒ๋ผ์šฐ์ €๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์— ๋Œ€ํ•ด ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋ฅผ ์ฐจ๋‹จํ•˜์ง€ ์•Š๊ณ  ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋™์‹œ์— ์ฒ˜๋ฆฌํ• ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

Web APIs

์˜ˆ๋ฅผ ๋“ค์–ด, setTimeout ๋น„๋™๊ธฐ ์ž‘์—…์€ Web APIs์˜ ํ•œ ์ข…๋ฅ˜์ธ Timer API ์—์„œ ํƒ€์ด๋จธ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํƒ€์ด๋จธ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, XMLHttpRequest , fetch์™€ ๊ฐ™์€ ๋„คํŠธ์›Œํฌ ๊ด€๋ จ API๋Š” ๋„คํŠธ์›Œํฌ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋„คํŠธ์›Œํฌ ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ์ฒ˜๋ฆฌ๋œ๋‹ค.

Web APIs

Web APIs์˜ ๋Œ€ํ‘œ์ ์ธ ์ข…๋ฅ˜๋กœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • DOM : HTML ๋ฌธ์„œ์˜ ๊ตฌ์กฐ์™€ ๋‚ด์šฉ์„ ํ‘œํ˜„ํ•˜๊ณ  ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด
  • XMLHttpRequest: ์„œ๋ฒ„์™€ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ตํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด. AJAX๊ธฐ์ˆ ์˜ ํ•ต์‹ฌ.
  • Timer API: ์ผ์ •ํ•œ ์‹œ๊ฐ„ ๊ฐ„๊ฒฉ์œผ๋กœ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜ ์ง€์—ฐ์‹œํ‚ค๋Š” ๋ฉ”์†Œ๋“œ๋“ค์„ ์ œ๊ณต
  • Console API : ๊ฐœ๋ฐœ์ž ๋„๊ตฌ์—์„œ ์ฝ˜์†” ๊ธฐ๋Šฅ์„ ์ œ๊ณต
  • Canvas API: <canvas> ์š”์†Œ๋ฅผ ํ†ตํ•ด ๊ทธ๋ž˜ํ”ฝ์„ ๊ทธ๋ฆฌ๊ฑฐ๋‚˜ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๋ฉ”์†Œ๋“œ๋“ค์„ ์ œ๊ณต
  • Geolocation API: ์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‚ฌ์šฉ์ž์˜ ํ˜„์žฌ ์œ„์น˜ ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ๋ฉ”์†Œ๋“œ๋“ค์„ ์ œ๊ณต

์ด๋•Œ ์˜คํ•ดํ•˜์ง€ ๋งํ•˜์•ผํ•  ๊ฒƒ์ด ๋ชจ๋“  Web API๋“ค์ด ๋น„๋™๊ธฐ๋กœ ๋™์ž‘๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค. Web API์—๋Š” ๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๋Š” ๊ฒƒ๊ณผ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๋Š” ๊ฒƒ์ด ๋ชจ๋‘ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด DOM API๋‚˜ Console API๋Š” ๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๊ณ , XMLHttpRequest๋‚˜ Timer API๋Š” ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค.

 

Callback Queue์˜ ์ข…๋ฅ˜

Web APIs๊ฐ€ ์—ฌ๋Ÿฌ API๋“ค์„ ๋ฌถ์–ด ๋งํ•˜๋“ฏ์ด, Callback Queue๋„ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ข…๋ฅ˜์˜ Queue๋ฅผ ๋ฌถ์–ด ์ด์นญํ•˜๋Š” ๊ฐœ๋…์ด๋‹ค. Callback Queue์—๋Š” (macro)task queue์™€ microtask queue ๋‘ ๊ฐ€์ง€ ์ข…๋ฅ˜๊ฐ€ ์žˆ๋‹ค. 

Callback Queue

  • Task Queue : setTimeout, setInterval, fetch, addEventListener ์™€ ๊ฐ™์ด ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌ๋˜๋Š” ํ•จ์ˆ˜๋“ค์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๊ฐ€ ๋“ค์–ด๊ฐ€๋Š” ํ (macrotask queue ๋Š” ๋ณดํ†ต task queue ๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค)
  • Microtask Queue : promise.then, process.nextTick, MutationObserver ์™€ ๊ฐ™์ด ์šฐ์„ ์ ์œผ๋กœ ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌ๋˜๋Š” ํ•จ์ˆ˜๋“ค์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๊ฐ€ ๋“ค์–ด๊ฐ€๋Š” ํ (์ฒ˜๋ฆฌ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์Œ)

Callback Queue์˜ ์ข…๋ฅ˜์— ๋”ฐ๋ผ ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ์ฝœ ์Šคํƒ์œผ๋กœ ์˜ฎ๊ธฐ๋Š” ์ˆœ์„œ๊ฐ€ ๋‹ฌ๋ผ์ง„๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ microtask queue๊ฐ€ ๊ฐ€์žฅ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์•„ ๋จผ์ € microtask queue๋ฅผ ์ฒ˜๋ฆฌํ•˜์—ฌ ๋จผ์ € ๋น„์šฐ๊ณ  ๊ทธ๋ผ์Œ task queue์˜ ์ฝœ๋ฐฑ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.

์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ๋ฐฐ์šฐ๊ธฐ ์ „์— Promise.then ๊ฒฐ๊ณผ๊ฐ€ setTimeout๋ณด๋‹ค ์šฐ์„  ๋œ๋‹ค๋Š” ๊ฒƒ์„ ๋ฏธ๋ฆฌ ๋ฐฐ์› ๋‹ค๋ฉด, ์™œ ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ๋จผ์ € ์ฒ˜๋ฆฌ๋˜๋Š”์ง€์— ๋Œ€ํ•œ ์ด์œ ๊ฐ€ ์ด๋ฒคํŠธ ๋ฃจํ”„์˜ ๋™์ž‘ ์›๋ฆฌ์™€ ๊ด€๋ จ์ด ์žˆ๋‹ค๋Š”๊ฑธ ์•Œ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

๋˜ํ•œ ๊ฐ™์€ queue ์•ˆ์— ์ ์žฌ๋˜๋Š” ์ฝœ๋ฐฑ์ด๋ผ๋„ ์–ด๋– ํ•œ ๋น„๋™๊ธฐ ์ž‘์—…์ด๋ƒ์— ๋”ฐ๋ผ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋‹ค๋ฅธ ํƒœ์Šคํฌ๋“ค์ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ๋“ค์–ด Microtask Queue์— ์ ์žฌ๋˜๋Š” Promise ์™€ Mutation Observer ์ฝœ๋ฐฑ ์ค‘ Mutation Observer์ด ๋จผ์ € ์ฒ˜๋ฆฌ๋˜๋Š” ์‹์ด๋‹ค.

 

AnimationFrame Queue

๋ธŒ๋ผ์šฐ์ €์˜ ํ๋Š” ์ฝœ๋ฐฑ ํ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ธŒ๋ผ์šฐ์ € ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ž‘์—…์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ๋‹ด๋‹นํ•˜๋Š” AnimationFrame Queue๋„ ์žˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋™์ž‘์„ ์ œ์–ดํ•˜๋Š” requestAnimationFrame ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ์ฝœ๋ฐฑ์„ ๋“ฑ๋กํ•˜๋ฉด, ์ด ํ์— ์ ์žฌ๋˜์–ด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ repaint ์ง์ „์— AnimationFrame Queue์— ์žˆ๋Š” ์ž‘์—…๋“ค์„ ์ „๋ถ€ ์ฒ˜๋ฆฌํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์Šคํƒ€์ผ ๊ด€๋ จ ์ฝ”๋“œ๋“ค์„ AnimationFrame Queue์— ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌํ•˜๋„๋ก ๊ตฌ์„ฑํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์• ๋‹ˆ๋ฉ”์ด์…˜์˜ ํƒ€์ด๋ฐ์„ ๊ด€๋ฆฌํ•˜๊ณ , ์ ์ ˆํ•œ ํ”„๋ ˆ์ž„ ์†๋„๋ฅผ ์œ ์ง€ํ•˜๊ณ , ๋‹ค๋ฅธ ํƒญ์ด๋‚˜ ์ฐฝ์— ์žˆ์„ ๋•Œ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ค‘์ง€ํ•จ์œผ๋กœ์จ ๋ธŒ๋ผ์šฐ์ €์˜ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋™์ž‘์˜ ์„ฑ๋Šฅ๊ณผ ํ’ˆ์งˆ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

 

๐ŸŒ ์›น ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ตœ์ ํ™” requestAnimationFrame ๊ฐ€์ด๋“œ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์›น ์• ๋‹ˆ๋ฉ”์ด์…˜ ์›นํŽ˜์ด์ง€์˜ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๊ตฌํ˜„ํ• ๋•Œ CSS์˜ animatoin , transition , transform ์†์„ฑ์„ ํ†ตํ•ด ๊ตฌํ˜„ํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ๋ณด๋‹ค ์‚ฌ์šฉ์ž์™€์˜ ๋ณต์žกํ•œ ์ƒํ˜ธ์ž‘์šฉ์„ ๊ตฌํ˜„ํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด Javasc

inpa.tistory.com


Node.js์˜ ๋‚ด๋ถ€ ๊ตฌ์„ฑ๋„

NodeJS ํ™˜๊ฒฝ์—์„œ๋„ ๋ธŒ๋ผ์šฐ์ €์™€ ๊ฑฐ์˜ ๋น„์Šทํ•œ ๊ตฌ์กฐ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ฐจ์ด์ ์ด ์žˆ๋‹ค๋ฉด ๋‚ด์žฅ๋œ libuv ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ IO๋ฅผ ์ง€์›ํ•œ๋‹ค๋Š” ์ ์ด๋‹ค. ๋˜ํ•œ ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” Web API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ DOM ์กฐ์ž‘, AJAX ํ˜ธ์ถœ, ํƒ€์ด๋จธ ๋ฐ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋“ฑ๊ณผ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜์ง€๋งŒ, Node.js์—์„œ๋Š” Web API๊ฐ€ ์•„๋‹Œ Node.js API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŒŒ์ผ ์‹œ์Šคํ…œ ์•ก์„ธ์Šค, ๋„คํŠธ์›Œํฌ ์•ก์„ธ์Šค, ์•”ํ˜ธํ™”, ์••์ถ• ๋ฐ ํ•ด์ œ ๋“ฑ๊ณผ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, Node.js์—์„œ HTTP ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด http ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•œ๋‹ค. ๋‹จ, Node.js์—์„œ๋„ ์ผ๋ถ€ Web API๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, setTimeout, setInterval ๋“ฑ์ด ๊ทธ๋ ‡๋‹ค.

Node.js

์ด์ฒ˜๋Ÿผ Node.js์—์„œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์€ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์œ„ํ•ด์„œ Node.js์˜ API๋ฅผ ํ˜ธ์ถœํ•˜๋ฉฐ, ์ด๋•Œ ๋„˜๊ฒจ์ง„ ์ฝœ๋ฐฑ์€ libuv ์˜ ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ํ†ตํ•ด ์Šค์ผ€์ฅด๋˜๊ณ  ์‹คํ–‰๋œ๋‹ค. Node.js์˜ ๋‚ด๋ถ€ ๊ตฌ์„ฑ์œผ๋กœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • V8 (JavaScript ์—”์ง„) : Node.js์—์„œ ์‚ฌ์šฉํ•˜๋Š” JavaScript ์—”์ง„์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ปดํŒŒ์ผํ•˜๊ณ  ์‹คํ–‰ํ•œ๋‹ค
  • Bindings (Node API) : Node.js ์‹œ์Šคํ…œ๊ณผ V8 ์—”์ง„ ๊ฐ„์˜ ์ƒํ˜ธ์ž‘์šฉ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋Š” C++ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • Libuv ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ : Node.js์—์„œ ๋น„๋™๊ธฐ I/O ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ C ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • Event Queue : ๋น„๋™๊ธฐ I/O ์ž‘์—… ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•˜๊ณ  ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ์ž๋ฃŒ๊ตฌ์กฐ (์›น๋ธŒ๋ผ์šฐ์ €์˜ Task Queue์™€ ๋น„์Šทํ•˜๋‹ค)
  • Event Loop : Event Queue์— ์ €์žฅ๋œ I/O ์ž‘์—… ๊ฒฐ๊ณผ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ , ๋‹ค์Œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ํ•˜๋Š” ๊ด€๋ฆฌ์ž
  • Worker Threads : CPU ์ง‘์•ฝ์ ์ธ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด Node.js 10 ๋ฒ„์ „๋ถ€ํ„ฐ ์ถ”๊ฐ€๋œ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ. worker threads๋Š” ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์™€ ๋…๋ฆฝ์ ์ธ V8 ์—”์ง„ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€์ง„๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ด๋ฒคํŠธ ๋ฃจํ”„ ๋™์ž‘ ๊ณผ์ •

์•ž์˜ ๋‚ด์šฉ์„ ๋ณต์Šตํ•˜์ž๋ฉด, ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ์ธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋„ ์ž‘์—…์˜ ๋™์‹œ ์ฒ˜๋ฆฌ์„ ์ง€์›ํ•  ์ˆ˜ ์žˆ๋Š” ๋น„๊ฒฐ์—๋Š” ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„๊ณผ ๋ธŒ๋ผ์šฐ์ €์˜ ์›น API๋ฅผ ์—ฐ๊ฒฐํ•˜์—ฌ ๋น„๋™๊ธฐ์ ์ธ ์ผ ์ฒ˜๋ฆฌ๋ฅผ ๊ฐ€๋Šฅ์ผ€ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋‹ค๋งŒ ๋ชจ๋“  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—๋Š” ๋น„๋™๊ธฐ๋กœ ๋™์ž‘ํ•˜๋Š” ๋น„๋™๊ธฐ ์ „์šฉ ํ•จ์ˆ˜๊ฐ€ ์žˆ๋Š”๋ฐ ๋Œ€ํ‘œ์ ์œผ๋กœ setTimeout ์ด๋‚˜ fetch, addEventListener ๊ฐ€ ์žˆ๋‹ค.

js-event-loop

๋ธŒ๋ผ์šฐ์ €์˜ Web APIs๋Š” ์œ„ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด ๊ฐ๊ฐ ์ „์šฉ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” API ์Šค๋ ˆ๋“œ๋“ค๋กœ ๊ตฌ์„ฑ๋œ ์ง‘ํ•ฉ์„ ๋งํ•œ๋‹ค. ๋”ฐ๋ผ์„œ setTimeout ์ด ํ˜ธ์ถœ๋˜๋ฉด Timer API ๋ผ๋Š” ๋ณ„๋„์˜ ์Šค๋ ˆ๋“œ์—์„œ ํƒ€์ด๋จธ ๋™์ž‘์ด ๋ณ„๋„๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ด๋ฉฐ, fetch ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด Ajax API ์Šค๋ ˆ๋“œ์—์„œ ๋„คํŠธ์›Œํฌ ํ†ต์‹ ์ด ์ด๋ฃจ์–ด ์ง€๋Š” ๊ฒƒ์ด๋‹ค.

์ด๋ฒคํŠธ ๋ฃจํ”„(Event Loop)๋Š” ์ด ๋น„๋™๊ธฐ ํ•จ์ˆ˜ ์ž‘์—…์„ Web API์— ์˜ฎ๊ธฐ๋Š” ์—ญํ• ์„ ํ•˜๊ณ  ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ์ฝœ๋ฐฑ์„ ํ(Queue)์— ์ ์žฌํ–ˆ๋‹ค๊ฐ€ ๋‹ค์‹œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์— ์ ์žฌํ•ด ์ˆ˜ํ–‰์‹œํ‚ค๋Š” ์ผ์ข…์˜ '์ž‘์—…์„ ์˜ฎ๊ธฐ๋Š” ์—ญํ• ' ๋งŒ์„ ํ•œ๋‹ค. ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ฃผ์ฒด๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„๊ณผ ์›น API ์ด๋‹ค. ๊ทธ๋ž˜์„œ ์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” Call Stack์— ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ ์ž‘์—…์ด ์žˆ๋Š”์ง€ ๊ทธ๋ฆฌ๊ณ  Task Queue์— ๋Œ€๊ธฐ ์ค‘์ธ ์ž‘์—…์ด ์žˆ๋Š”์ง€ ๋ฐ˜๋ณต์ ์œผ๋กœ ํ™•์ธํ•˜๋Š” ์ผ์ข…์˜ ๋ฌดํ•œ ๋ฃจํ”„๋งŒ์„ ๋Œ๊ณ , ๋Œ€๊ธฐ ์ž‘์—…์ด ์žˆ๋‹ค๋ฉด ์ž‘์—…์„ ์˜ฎ๊ฒจ์ฃผ๋Š” ํ˜•ํƒœ๋กœ ๋™์ž‘ํ•œ๋‹ค๊ณ  ๋ณด๋ฉด ๋œ๋‹ค. (๊ทธ๋ž˜์„œ ์ด๋ฒคํŠธ '๋ฃจํ”„' ์ด๋‹ค)

// ์ด๋ฒคํŠธ ๋ฃจํ”„์˜ ๋™์ž‘์„ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฐ€์ƒ์˜ ์ฝ”๋“œ
while(queue.waitForMessage()){ // ํ์— ๋ฉ”์‹œ์ง€๊ฐ€ ์žˆ์„ ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
  queue.processNextMessage(); // ๊ฐ€์žฅ ์˜ค๋ž˜๋œ ๋ฉ”์‹œ์ง€๋ฅผ ํ์—์„œ ๊บผ๋‚ด์„œ ํ˜ธ์ถœ ์Šคํƒ์œผ๋กœ ์˜ฎ๊น€
}

์ง€๊ธˆ๋ถ€ํ„ฐ ์•Œ์•„๋ณผ ์ด๋ฒคํŠธ ๋ฃจํ”„ ๋™์ž‘ ๊ณผ์ •์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๊ฐ€ ๋ธŒ๋ผ์šฐ์ € ๋‚ด๋ถ€์—์„œ ์ž‘์—… ์ด๋™์ด ์–ด๋– ํ•œ ํ˜•์‹์œผ๋กœ ์–ด๋– ํ•œ ์›๋ฆฌ๋กœ ์ง„ํ–‰์ด ๋˜๋Š”์ง€ ์•Œ์•„๋ณด๋Š” ๊ฒƒ์ด๋‹ค. ๋งˆ์นจ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ด๋ฒคํŠธ ๋ฃจํ”„ ๊ณผ์ •์„ Lydia Hellie ๋ถ„์ด ์•„์ฃผ ๊ณ ํ€„๋ฆฌํ‹ฐ๋กœ gif ์• ๋‹ˆ๋ฉ”์ด์…˜์œผ๋กœ ํ‘œํ˜„ํ•œ ์ด๋ฏธ์ง€๊ฐ€ ์žˆ์–ด์„œ ์ด๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ์†Œ๊ฐœํ•ด๋ณธ๋‹ค.


setTimeOut ๋‚ด๋ถ€ ๋™์ž‘ ๊ณผ์ •

์šฐ์„  ๊ฐ€์žฅ ํ”ํ•œ ํƒ€์ด๋จธ ๋น„๋™๊ธฐ ํ•จ์ˆ˜์˜ ์ด๋ฒคํŠธ ๋ฃจํ”„ ๊ณผ์ •์„ ์•Œ์•„๋ณด๋„๋ก ํ•˜์ž.

function bar() {
  setTimeout(() => {
  	console.log("Second")
  }, 500);
}

function foo() {
  console.log("First");
}

function baz() {
  console.log("Third");
}

bar();
foo();
baz();

์œ„์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ ์‹คํ–‰ ๊ณผ์ •์€ ๋‹ค์Œ์˜ ์ˆœ์„œ๋กœ ์ง„ํ–‰๋œ๋‹ค.

setTimeOut

  1. bar() ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ  ๊ทธ์•ˆ์˜ setTimeout() ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜์–ด ์Šคํƒ์— ์Œ“์ธ๋‹ค.
  2. setTimeout() ํ•จ์ˆ˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜์— ํ• ๋‹น๋œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ Timer Web API์— ์ „๋‹ฌํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Timer Web API ์—์„œ๋Š” ๋ฐฑ๊ทธ๋ผ์šด๋“œ๋กœ 500 ๋ฐ€๋ฆฌ์ดˆ๋ฅผ ์…ˆํ•œ๋‹ค.
  3. ๋‹ค์Œ foo() ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ  ์ฝ˜์†”์ฐฝ(output)์— "First" ๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.
  4. ์ด๋•Œ 500 ๋ฐ€๋ฆฌ์ดˆ ๋Œ€๊ธฐ ์‹œ๊ฐ„์ด ๋งŒ๋ฃŒ๋˜๋ฉด์„œ, ์ด๋ฒคํŠธ ๋ฃจํ”„๋Š”Timer Web API์—์„œ ๊ฐ€์ง€๊ณ  ์žˆ๋˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ Task Queue ๋กœ ์˜ฎ๊ธด๋‹ค.
  5. ๊ทธ๋‹ค์Œ baz() ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ  ์ฝ˜์†”์ฐฝ์— "Third" ๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.
  6. ์Šคํƒ์— ์žˆ๋Š” ๋ชจ๋“  ๋ฉ”์ธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰ ์™„๋ฃŒ ๋˜์–ด Call Stack์ด ๋น„์›Œ์ง€๊ฒŒ ๋œ๋‹ค.
  7. ์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” Call Stack ์ด ๋น„์–ด์žˆ๋Š” ๊ฒฝ์šฐ๋ฅผ ํƒ์ง€ํ•˜์—ฌ, Task Queue ์— ์žˆ๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ Call Stack ์œผ๋กœ ์˜ฎ๊ธด๋‹ค.
  8. Call Stack ์—์„œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ฒŒ ๋˜๊ณ  ์ฝœ์†”์ฐฝ์—๋Š” "Second" ๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.

์ด ๋™์ž‘ ์›๋ฆฌ์˜ ํ•ต์‹ฌ์€ ํŠน์ •ํ•œ ์ž‘์—…์— ๋Œ€ํ•ด ๋น„๋™๊ธฐ๋กœ ๋ฉ€ํ‹ฐ ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋น„๋™๊ธฐ ๋™์ž‘ ์˜ˆ์‹œ๊ฐ€ ๊ณ ์ž‘ ํƒ€์ด๋จธ๋ฅผ ์…ˆํ•˜๋Š” setTimeout ์ด๋ผ ์ž˜ ์™€๋‹ฟ์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ํŒŒ์ผ ์ž…์ถœ๋ ฅ์ด๋‚˜ ํ‚ค๋ณด๋“œ ํƒ€์ดํ•‘ ํ•˜๋Š” ์ด๋ฒคํŠธ ๋™์ž‘์ผ ๊ฒฝ์šฐ๋ผ๋ฉด ์–ด๋–ป๊นŒ? ๋น„๋™๊ธฐ๊ฐ€ ์—†๋‹ค๋ฉด ํŒŒ์ผ์„ ๋‹ค์šด ๋ฐ›๊ฑฐ๋‚˜ ํ‚ค๋ณด๋“œ๋ฅผ ํƒ€์ดํ•‘ ํ•˜๋Š” ๋™์•ˆ์—๋Š” ๋™์•ˆ ์›น์‚ฌ์ดํŠธ๋Š” ๋ฉˆ์ถ”๊ฒŒ ๋˜์–ด ์•„๋ฌด๊ฒƒ๋„ ๋ชปํ•˜๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค. ๋ฐ”๋กœ ์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” ์ด๋Ÿฌํ•œ ์ž‘์—…๋“ค์„ ๋ณ„๋„๋กœ ๋ธŒ๋ผ์šฐ์ €์˜ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ์—๊ฒŒ ์ธ๊ฐ€ํ•˜์—ฌ ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌํ•ด์ฃผ๋Š” ํ•ธ๋“ค๋Ÿฌ ์—ญํ• ์„ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

 

์›น๋ธŒ๋ผ์šฐ์ €์™€ Node.js์˜ Web API ์ฐจ์ด

์›น๋ธŒ๋ผ์šฐ์ €์˜ Web APIs ์™€ Node.js ์˜ Node.js APIs ๋“ค์€ ๊ตฌ์„ฑ์€ ๋น„์Šทํ•˜์ง€๋งŒ ๋™์ž‘ ์ธก๋ฉด์—์„œ ์•ฝ๊ฐ„ ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค. ์›น๋ธŒ๋ผ์šฐ์ €์˜ Web APIs๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์ด ๋๋‚˜๋ฉด ์Šค์Šค๋กœ callback queue์— ์ ์žฌํ•˜์ง€๋งŒ, Node.js API๋“ค์€ ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ์ง์ ‘ ์˜ฎ๊ฒจ์ค€๋‹ค. ์˜ˆ๋ฅผ๋“ค์–ด Timer Web API์—์„œ ํƒ€์ด๋จธ๊ฐ€ ๋ชจ๋‘ ์ง€๋‚˜๊ฐ€๋ฉด, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ™˜๊ฒฝ์ด ์›น๋ธŒ๋ผ์šฐ์ €๋ƒ Node.js ๋ƒ์— ๋”ฐ๋ผ ์ฐจ์ด๊ฐ€ ๊ฐˆ๋ฆฐ๋‹ค.

  • Node.js : Timer API๊ฐ€ ํƒ€์ด๋จธ ์™„๋ฃŒ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ณ , ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ์ด๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ Task Queue์— ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
  • ์›น๋ธŒ๋ผ์šฐ์ € : Timer API๊ฐ€ ์Šค์Šค๋กœ Task Queue์— ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

Promise ๋‚ด๋ถ€ ๋™์ž‘ ๊ณผ์ •

 

Task Queue ์™€ Microtask Queue

Callback Queue๋Š” Web API๊ฐ€ ์ˆ˜ํ–‰ํ•œ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ๋„˜๊ฒจ๋ฐ›์•„ Event Loop๊ฐ€ ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ Call Stack์— ๋„˜๊ฒจ์ค„ ๋•Œ๊นŒ์ง€ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋“ค์„ ์Œ“์•„๋†“๋Š” ๊ณณ์ด๋‹ค. ์œ„์—์„œ Callback Queue์˜ ์ข…๋ฅ˜์—๋Š” (Macro)Task Queue, MicroTask Queue 2๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•˜์˜€๋Š”๋ฐ, ๊ทธ์ค‘ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ Promise ๊ฐ์ฒด์˜ ์ฝœ๋ฐฑ์ด ์Œ“์ด๋Š” ๊ณณ์ด ๋ฐ”๋กœ MicroTask Queue์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  MicroTask Queue๋Š” ๊ทธ ์–ด๋–ค ๊ณณ๋ณด๋‹ค ๊ฐ€์žฅ ๋จผ์ € ์šฐ์„ ์œผ๋กœ ์ฝœ๋ฐฑ์ด ์ฒ˜๋ฆฌ๋˜๊ฒŒ ๋œ๋‹ค. (์‹ฌ์ง€์–ด ๋ธŒ๋ผ์šฐ์ € ํ™”๋ฉด ๋ Œ๋”๋งํ•˜๊ธฐ ์ „๋ณด๋‹ค ๋ง์ด๋‹ค)

Event-Loop

 

MicroTask Queue ์ฒ˜๋ฆฌ ๊ณผ์ •

์‹ค์ œ ์˜ˆ์‹œ ์ฝ”๋“œ์—์„œ setTimeout ๊ฐ€ Promise ๊ฐ์ฒด์˜ ์ฝœ๋ฐฑ์ด ๋™์‹œ์— ์ฃผ์–ด์กŒ์„๋•Œ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌ๋˜๋Š”์ง€ ํ™•์ธํ•ด๋ณด์ž. ์ฝ”๋“œ ๋‚ด์šฉ์„ ์‚ดํŽด๋ณด๋ฉด ๋จผ์ € setTimeout ์„ ํ†ตํ•ด์„œ 0์ดˆ๋™์•ˆ ๋Œ€๊ธฐ ํ•˜์˜€๋‹ค๊ฐ€ "Timeout!" ์„ ์ถœ๋ ฅํ•˜๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. ๊ทธ๋‹ค์Œ Promise ๊ฐ์ฒด์— ์˜ํ•ด "Promise!" ๋ผ๋Š” ํ…์ŠคํŠธ๋ฅผ ์ถœ๋ ฅํ•˜๋Š” then ํ•ธ๋“ค๋Ÿฌ์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. ์ด ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ๋™์ž‘ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ๋ฐœ์ƒํ•œ๋‹ค.

console.log('Start!');

setTimeout(() => {
	console.log('Timeout!');
}, 0);

Promise.resolve('Promise!').then(res => console.log(res));

console.log('End!');

 

1. Call Stack์— console.log('Start!') ์ฝ”๋“œ ๋ถ€๋ถ„์ด ์Œ“์ธ ๋’ค ์‹คํ–‰ ๋˜์–ด ์ฝ˜์†”์ฐฝ์— "Start!" ๊ฐ€ ์ถœ๋ ฅ

Event-Loop

 

2. setTimeout ์ฝ”๋“œ๊ฐ€ ์ฝœ ์Šคํƒ์— ์ ์žฌ๋˜๊ณ  ์‹คํ–‰๋˜๋ฉด, ๊ทธ ์•ˆ์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๊ฐ€ ์ด๋ฒคํŠธ ๋ฃจํ”„์— ์˜ํ•ด Web API๋กœ ์˜ฎ๊ฒจ์ง€๊ณ  ํƒ€์ด๋จธ๊ฐ€ ์ž‘๋™ํ•˜๊ฒŒ ๋œ๋‹ค. (0์ดˆ๋ผ์„œ ์‚ฌ์‹ค์ƒ ๋ฐ”๋กœ ํƒ€์ด๋จธ๋Š” ์ข…๋ฃŒ๋œ๋‹ค)

Event-Loop

 

3. ํƒ€์ด๋จธ๊ฐ€ ์ข…๋ฃŒ๋จ์— ๋”ฐ๋ผ setTimeout ์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” MacroTask Queue์— ์ด๋ฒคํŠธ ๋ฃจํ”„์— ์˜ํ•ด ์ ์žฌ๋˜๊ฒŒ ๋œ๋‹ค.

4. Promise ์ฝ”๋“œ๊ฐ€ ์ฝœ์Šคํƒ์— ์ ์žฌ ๋˜์–ด ์‹คํ–‰๋˜๊ณ  then ํ•ธ๋“ค๋Ÿฌ์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๊ฐ€ ์ด๋ฒคํŠธ ๋ฃจํ”„์— ์˜ํ•ด MicroTask Queue์— ์ ์žฌ๋˜๊ฒŒ ๋œ๋‹ค.

Event-Loop

 

5. console.log('End!') ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ณ  "End!" ํ…์ŠคํŠธ๊ฐ€ ์ฝ˜์†”์ฐฝ์— ์ถœ๋ ฅ๋œ๋‹ค.

Event-Loop

 

6. ๋ชจ๋“  ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰์ด๋˜์–ด ๋”์ด์ƒ Call Stack์—” ์‹คํ–‰ํ•  ์Šคํƒ์ด ์—†์–ด ๋น„์›Œ์ง€๊ฒŒ ๋œ๋‹ค.

7. ๊ทธ๋Ÿฌ๋ฉด ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์ด๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ, Callback Queue์— ๋‚จ์•„์žˆ๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋“ค์„ ๋นผ์™€ Call Stack์— ์ ์žฌํ•˜๊ฒŒ ๋œ๋‹ค.

8. ์ด๋•Œ 2์ข…๋ฅ˜์˜ Queue ์ค‘ MicroTask Queue์— ๋‚จ์•„์žˆ๋Š” ์ฝœ๋ฐฑ์ด ์šฐ์„ ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค. (๋งŒ์ผ ์ฝŸ๊ฐœ์ด ์—ฌ๋Ÿฌ๊ฐœ๊ฐ€ ์žˆ๋‹ค๋ฉด ์ „๋ถ€ ์ฒ˜๋ฆฌ๋œ๋‹ค)

Event-Loop

 

9. MicroTask Queue๊ฐ€ ๋น„์–ด์ง€๋ฉด, ์ด์ œ ์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” MacroTask Queue์— ์žˆ๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ Call Stack์— ์ ์žฌํ•ด ์‹คํ–‰๋˜๊ฒŒ ๋œ๋‹ค.

Event-Loop

 

๋”ฐ๋ผ์„œ ์ตœ์ข… ์ฝ”๋“œ์˜ ์‹คํ–‰ ์ˆœ์„œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋œ๋‹ค.

Event-Loop


Async/Await ๋‚ด๋ถ€ ๋™์ž‘ ๊ณผ์ •

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ Async/Await ๋Š” ๋น„๋™๊ธฐ ๋…ผ๋ธ”๋กœํ‚น ๋™์ž‘์„ ๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ES7 ๋ถ€ํ„ฐ ์ƒˆ๋กญ๊ฒŒ ๋„์ž…๋œ ๊ฒƒ์œผ๋กœ ๋ณต์žกํ•œ ์ฝœ๋ฐฑ์ด๋‚˜ then ํ•ธ๋“ค๋Ÿฌ์˜ ์ง€์˜ฅ(hell) ์ฝ”๋“œ๋ฅผ ๊ทน๋ณตํ•˜๋Š” ํ•ต์‹ฌ์ด๋‹ค. Async/Await ์˜ ๊ธฐ๋ณธ์ ์ธ ์‚ฌ์šฉ ๋ฌธ๋ฒ•์— ๋Œ€ํ•ด์„œ๋Š” ๋…์ž๋ถ„๋“ค๋„ ์ตํžˆ ์•Œ๊ณ  ์žˆ์„ ๊ฒƒ์ด๋‹ค. ํ•˜์ง€๋งŒ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด Async/Await ์„ ๋‹จ์ˆœํžˆ ๋น„๋™๊ธฐ๋ฅผ ๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์ค€๋‹ค๋Š” ํšจ๊ณผ๋งŒ ์•Œ๊ณ ์žˆ์–ด์„œ์ธ์ง€, ๋น„๋™๊ธฐ ์ฝ”๋“œ์™€ ๋™๊ธฐ ์ฝ”๋“œ๊ฐ€ ๊ฐ™์ด ์“ฐ์—ฌ์ ธ ์žˆ์„ ๊ฒฝ์šฐ ์ด๋“ค์˜ ํ™•์‹คํ•œ ์ฒ˜๋ฆฌ ๊ณผ์ •์„ ์ •ํ™•ํ•˜๊ฒŒ ์•Œ์ง€ ๋ชปํ•œ๋‹ค.

์˜ˆ๋ฅผ๋“ค์–ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด async ํ•จ์ˆ˜๋ฅผ ๋™์ผ ์ฝ”๋“œ ๋ ˆ๋ฒจ์—์„œ ์‹คํ–‰ํ•œ๋‹ค๊ณ  ํ•ด๋ณด์ž.

const one = () => Promise.resolve('One!');

async function myFunc(){
	console.log('In function!');
	const res = await One();
	console.log(res);
}

console.log('Before Function!');
myFunc();
console.log('After Function!');

 

1. ์ฝ˜์†”์— 'Before Function!' ์ด ์ถœ๋ ฅ๋œ๋‹ค.

Event-Loop

 

2. async ํ•จ์ˆ˜์ธ myFunc() ์ด ํ˜ธ์ถœ๋œ๋‹ค.

3. async ํ•จ์ˆ˜ ์•ˆ์— ์žˆ๋Š” ์ฝ˜์†” ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜์–ด ์ฝ˜์†”์— 'In Function!' ์ด ์ถœ๋ ฅ๋œ๋‹ค.

๊ฐ€๋” async ํ•จ์ˆ˜๋ฅผ ๋ฉ”์ธ ์ฝ”๋“œ๊ฐ€ ๋ชจ๋‘ ์‹คํ–‰๋˜์–ด์•ผ ๋‚˜์ค‘์— ์‹คํ–‰๋˜๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋กœ ์•Œ๊ณ  ์žˆ๋Š” ์‚ฌ๋žŒ๋“ค์ด ๋งŽ์€๋ฐ, async ํ•จ์ˆ˜๋Š” ๋ธ”๋Ÿญ ๋‚ด๋ถ€์—์„œ await ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ํ•จ์ˆ˜ ํ‚ค์›Œ๋“œ ์ผ ๋ฟ ๊ทธ๋ƒฅ ํ”„๋กœ๋ฏธ์Šค ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์กฐ๊ธˆ ํŠน๋ฒฝํ•œ ์ผ๋ฐ˜์ ์ธ ํ•จ์ˆ˜์ด๋‹ค. ๋”ฐ๋ผ์„œ async ํ•จ์ˆ˜๋ผ๋„ ์ผ๋ฐ˜ ํ•จ์ˆ˜์ฒ˜๋Ÿผ ํ˜ธ์ถœ ์Šคํƒ์ด ์Œ“์ด๊ณ , async ํ•จ์ˆ˜ ๋‚ด์˜ ๋น„๋™๊ธฐ๊ฐ€ ์•„๋‹Œ ๋™๊ธฐ ์ฝ”๋“œ๋Š” ์ผ๋ฐ˜ ์ฝ”๋“œ์™€ ๊ฐ™์ด ์‹คํ–‰๋œ๋‹ค.

Event-Loop

 

4. Promise ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” one() ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

5. ์ด๋•Œ one() ๋น„๋™๊ธฐ ํ•จ์ˆ˜ ์™ผ์ชฝ์— await ํ‚ค์›Œ๋“œ๋กœ ์ธํ•ด, myFunc ํ•จ์ˆ˜์˜ ๋‚ด๋ถ€ ์‹คํ–‰์€ ์ž ์‹œ ์ค‘๋‹จ๋˜๊ณ  Call stack ์—์„œ ๋น ์ ธ๋‚˜์™€ ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„์€ Microtask Queue ์— ์ ์žฌ๋œ๋‹ค. ์ด๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์ด await ํ‚ค์›Œ๋“œ๋ฅผ ์ธ์‹ํ•˜๋ฉด async ํ•จ์ˆ˜์˜ ์‹คํ–‰์€ ์ง€์—ฐ๋˜๋Š” ๊ฒƒ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

Event-Loop

 

6. ๋งˆ์ง€๋ง‰์œผ๋กœ ์ฝ˜์†”์— 'After Function!' ์ด ์ถœ๋ ฅ๋œ๋‹ค.

Event-Loop

 

7. ๋ชจ๋“  ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰์ด๋˜์–ด ๋”์ด์ƒ Call Stack์—” ์‹คํ–‰ํ•  ์Šคํƒ์ด ์—†์–ด ๋น„์›Œ์ง€๊ฒŒ ๋œ๋‹ค.

8. ๊ทธ๋Ÿฌ๋ฉด ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์ด๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ, Microtask Queue์— ๋‚จ์•„์žˆ๋Š” async ํ•จ์ˆ˜๋ฅผ ๋นผ์™€ Call Stack์— ์ ์žฌํ•˜๊ฒŒ ๋œ๋‹ค.

8. Promise ๊ฐ์ฒด์˜ ๊ฒฐ๊ณผ๋ฌผ์ธ 'One!' ๋ฌธ์ž์—ด์„ ๋ณ€์ˆ˜ res ์— ๋ฐ›๊ณ  ์ด๋ฅผ ์ฝ˜์†”์— ์ถœ๋ ฅํ•œ๋‹ค.

Event-Loop

 

Async/Await ์˜คํ•ด์™€ ์ง„์งœ ๋™์ž‘

๊ทธ๋Ÿผ ์ด๋ฒˆ์—๋Š” myFunc() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฉ”์ธ ์Šคํƒ์—์„œ await ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์—ฌ์ฃผ๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ์ฐธ๊ณ ๋กœ ์ตœ์‹  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” ์ตœ์ƒ์œ„ await ์„ ์ง€์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณ„๋„๋กœ ์ฆ‰์‹œ ์‹คํ–‰ IIFE๋ฅผ ๋ฌถ์ง€ ์•Š์•„๋„ ๋™์ž‘์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

const one = () => Promise.resolve('One!');

async function myFunc(){
	console.log('In function!');
	const res = await one();
	console.log(res);
}

console.log('Before Function!');
await myFunc();
console.log('After Function!');

Event-Loop

์ถœ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด, ์œ„์˜ Async/Await ์ฒ˜๋ฆฌ ๊ณผ์ • 1 ๊ณผ ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค๋Š”๊ฑธ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์ผ๋‹จ ๊ธฐ๋ณธ์ ์ธ Async/Await ๋ฌธ๋ฒ• ๊ฐœ๋…์„ ์•Œ๊ณ  ์žˆ๋‹ค๋ฉด ์ด ๋ถ€๋ถ„์€ ๊ทธ๋ ‡๊ฒŒ ์–ด๋ ต์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค. ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ๋Š” ์ง€๊ธˆ ์ด๋ฒคํŠธ ๋ฃจํ”„ ๋™์ž‘์— ๋Œ€ํ•ด ๋ฐฐ์šฐ๊ณ  ์žˆ๋‹ค. ๊ทธ๋Ÿผ ์ € ์ตœ์ƒ์œ„ await ์ฝ”๋“œ ๋™์ž‘์„ ์ด๋ฒคํŠธ ๋ฃจํ”„๋กœ ๋‚ด๋ถ€์ ์œผ๋กœ ๋”ฐ์ ธ๋ณด์ž. 

์•„๋งˆ ๋งŽ์€ ์ƒˆ๋‚ด๊ธฐ๋“ค์ด ์—ฌ๊ธฐ์„œ ๋ง‰ํž ๊ฒƒ์ด๋‹ค. ์šฐ๋ฆฌ๋Š” await ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” Promise ๋ฐ˜ํ™˜ ๋น„๋™๊ธฐ one() ํ•จ์ˆ˜์˜ ๊ฒฐ๊ณผ ์ฝœ๋ฐฑ์ด Microtask Queue์— ์ ์žฌ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ Microtask Queue์˜ ์ฝœ๋ฐฑ๋“ค์€ ์šฐ์„  ๋ฉ”์ธ Call Stack์ด ๋น„์›Œ์ ธ ์žˆ์–ด์•ผ ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ์˜ฎ๊ฒจ ์ฒ˜๋ฆฌํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์•„์ง ๋ฉ”์ธ Call Stack์—๋Š” console.log(‘After Function!’) ์ด ๋‚จ์•„ ์žˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด console.log(‘After Function!’) ์ด ์‹คํ–‰๋˜๊ธฐ ์ „์— await myFunc() ๋จผ์ € ์ฒ˜๋ฆฌ๋˜๊ณ  ์ฝ˜์†”์„ ์ถœ๋ ฅํ•จ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

์ด๊ฒŒ ์–ด๋–ป๊ฒŒ ๋œ ์ผ ์ผ๊นŒ? ์šฐ๋ฆฌ๊ฐ€ ์ง€๊ธˆ๊นŒ์ง€ ๋ฐฐ์šด ์ด๋ฒคํŠธ ๋ฃจํ”„ ๋™์ž‘์ด ์ž˜๋ชป๋œ ๊ฒƒ์ผ๊นŒ? 

์‚ฌ์‹ค Async/Await์˜ ์ง„์งœ ๋™์ž‘์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•˜์ž.

let x = await bar(); // bar() ํ•จ์ˆ˜ ์ •์˜๋Š” ์ƒ๋žต
console.log(x);
console.log('Done');

์œ„์˜ ์ฝ”๋“œ๋Š” ์‚ฌ์‹ค ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ์™€ ๊ฐ™์€ ์˜๋ฏธ๋ฅผ ๊ฐ€์ง„๋‹ค.  

bar().then(x => { 
    console.log(x); 
    console.log('Done'); 
});

์ฆ‰, await ํ‚ค์›Œ๋“œ ๋‹ค์Œ์— ๋‚˜์˜ค๋Š” ๋™์ผ ๋ผ์ธ์˜ ์ฝ”๋“œ๋“ค์€ ๋ชจ๋‘ await bar() ์˜ then ํ•ธ๋“ค๋Ÿฌ์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋กœ ๋“ค์–ด๊ฐ„๋‹ค๋Š” ๋œป์ด๋‹ค.

์‹ค์ œ๋กœ async/await ํ‚ค์›Œ๋“œ๋Š” promise.then() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ ๋„ ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋ฌธ๋ฒ•์ ์ธ ํŽธ์˜ ๊ธฐ๋Šฅ(syntactic sugar)์ผ ๋ฟ์ด๋‹ค. ์ฆ‰, async/await ํ‚ค์›Œ๋“œ๋Š” promise.then() ๋ฉ”์†Œ๋“œ๋ฅผ ๋Œ€์ฒดํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, promise.then() ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ณ  ๋ช…ํ™•ํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

๋”ฐ๋ผ์„œ ์ตœ์ข… ์ •๋ฆฌํ•˜์ž๋ฉด myFunc() ์ฝ”๋“œ๋Š” ํ”„๋กœ๋ฏธ์Šค ํ•ธ๋“ค๋Ÿฌ๋กœ ํ’€๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ๊ตฌ์„ฑ๋˜๊ฒŒ ๋˜๊ณ , ๊ฐ then ํ•ธ๋“ค๋Ÿฌ๋“ค์ด MicroTask Queue์— ์ฐจ๊ณก ์ฐจ๊ณก ์Œ“์ž„์œผ๋กœ์จ ์ˆœ์„œ๋Œ€๋กœ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

const one = () => Promise.resolve('One!');

async function myFunc(){
	console.log('In function!');
	const res = await one();
	console.log(res);
}

console.log('Before Function!');
await myFunc();
console.log('After Function!');

/* ---------------- ↓↓↓ ๋ณ€ํ™˜ ↓↓↓ ---------------- */

const one = () => Promise.resolve('One!'); 

function myFunc(){
	console.log('In function!');
	return one().then(res => {
	  console.log(res);
	});
}

console.log('Before Function!');
myFunc().then(() => {
  console.log('After Function!');
});

์ฆ‰, await myFunc() ๋‹ค์Œ์— ๋‚˜์˜ค๋Š” ์ฝ”๋“œ๋“ค์ด myFunc()์˜ then ํ•ธ๋“ค๋Ÿฌ์˜ ์ฝœ๋ฐฑ์œผ๋กœ์„œ Microtask Queue์— ์ ์žฌ๋˜๊ณ  ์ด๋ฒคํŠธ ๋ฃจํ”„์— ๋‹ค์‹œ Call stack์— ์˜ฎ๊ฒจ์ ธ์„œ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ด๋‹ค.


MicroTask Queue์˜ ๋ฌดํ•œ ๋ฃจํ”„

Task Queue์™€ MicroTask Queue์˜ ์ฐจ์ด์ ์€ ๋‹จ์ˆœํ•œ ์šฐ์„ ์ˆœ์œ„ ์ฐจ์ด ์ •๋„ ๋ฐ–์— ์—†์ง€๋งŒ, ์ข€๋” ํ™•์žฅํ•ด์„œ ๋ธŒ๋ผ์šฐ์ € ๋™์ž‘ ๊ด€์ ์—์„œ ๋ณด๋ฉด ์ด๋Š” ๊ต‰์žฅํžˆ ์ค‘์š”ํ•œ ์š”์†Œ์ด๋‹ค. MicroTask Queue์˜ ์ฝœ๋ฐฑ์€ ๊ฐ€์žฅ ๋†’์€ ์šฐ์„  ์ˆœ์œ„๋กœ ์ฒ˜๋ฆฌ๋˜์ง€๋งŒ ์ด๋Š” ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ™”๋ฉด์„ ๋ Œ๋”๋งํ•˜๋Š” ๊ณผ์ •๋ณด๋‹ค ๋” ๋จผ์ € ์ฒ˜๋ฆฌ๋˜๊ฒŒ ๋˜๋Š”๋ฐ, ๋งŒ์ผ MicroTask Queue์— ์ž˜๋ชป๋œ ๋ฌดํ•œ ๋ฃจํ”„ ๋™์ž‘์˜ ๋ฒ„๊ทธ์˜ ์ฝ”๋“œ๊ฐ€ ๋“ค์–ด๊ฐ€๊ฒŒ ๋˜๋ฉด ์›นํŽ˜์ด์ง€๊ฐ€ ๋จนํ†ต์ด ๋˜์–ด๋ฒ„๋ฆฌ๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ๋ด๋ณด์ž. ๋ฒ„ํŠผ์ด ํ•˜๋‚˜ ์žˆ๊ณ  ์—ฌ๊ธฐ์— ์ด๋ฒคํŠธ ์ฝœ๋ฐฑ์ด ๋“ฑ๋ก ๋˜์–ด ์žˆ๋‹ค. ์ด ์ด๋ฒคํŠธ ์ฝœ๋ฐฑ์€ Task Queue์— ์ ์žฌ๋˜์–ด ์‹คํ–‰๋˜๊ฒŒ ๋œ๋‹ค.

<button id="btn">Click me</button>

<script>
  // ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์ฝ˜์†”์— Clicked๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.
  document.getElementById("btn").addEventListener("click", () => {
    document.body.insertAdjacentHTML('beforeend', "<p>Clicked</p>");
  });
</script>

See the Pen MicroTask Queue์˜ ๋ฌดํ•œ ๋ฃจํ”„ 1 by barzz12 (@inpaSkyrim) on CodePen.

์ด ์ƒํƒœ์—์„œ ํ•œ๋ฒˆ setTimeout ๋ฌดํ•œ ๋ฃจํ”„๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด์ž. ์•„๋ž˜ '๋ฌดํ•œ๋ฃจํ”„ ์‹œ์ž‘' ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ํƒ€์ด๋จธ๊ฐ€ ๊ณ„์† ๋Œ์—ฌ "Loop" ์ฝ˜์†”์„ ์ถœ๋ ฅํ•  ๊ฒƒ์ด๋‹ค. ๊ทธ ์ƒํƒœ์—์„œ ๋ฒ„ํŠผ์„ Click me ํ•ด๋ณด์ž. ์•„๋ฌด ์ด์ƒ ์—†์ด ํ™”๋ฉด์— 'Clicked'๊ฐ€ ํ‘œ์‹œ๋  ๊ฒƒ์ด๋‹ค.

setTimeout ์˜ ๋ฃจํ”„ ์ฝœ๋ฐฑ์ด Task Queue์— ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ ์žฌ๋˜๋ฉด์„œ ์ฒ˜๋ฆฌ๋˜๋Š” ๋„์ค‘, ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋ฉด ์ด๋ฒคํŠธ ์ฝœ๋ฐฑ ์—ญ์‹œ Task Queue์— ์ ์žฌ๋˜์–ด ์‹คํ–‰์ด ๋˜๊ธฐ ๋•Œ๋ฌธ์—, ๋น„๋ก ๋ฌดํ•œ ๋ฃจํ”„ ์ฝ”๋“œ๋ผ๋„ ๋ธŒ๋ผ์šฐ์ € ๋™์ž‘ ์ž์ฒด๋Š” ๋ฌธ์ œ์—†๋Š” ๊ฒƒ์ด๋‹ค.

<button id="btn">Click me</button>
<button id="btn2">๋ฌดํ•œ๋ฃจํ”„ ์‹œ์ž‘</button>

<div id="loopArea" style="border: 1px solid black; max-height: 150px; overflow-y: auto;"></div>

<script>
  // ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์ฝ˜์†”์— Clicked๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.
  document.getElementById("btn").addEventListener("click", () => {
    document.body.insertAdjacentHTML('beforeend', "<p>Clicked</p>");
  });

  document.getElementById("btn2").addEventListener("click", () => {
    // setTimeout ํ•จ์ˆ˜๋Š” Task Queue์— ์ฝœ๋ฐฑ์„ ์ถ”๊ฐ€
    function loop() {
      setTimeout(() => {
        document.getElementById("loopArea").append("Loop\n");
        loop(); // loop ํ•จ์ˆ˜๊ฐ€ setTimeout ๊ฐ์ฒด์˜ ์ฝœ๋ฐฑ์œผ๋กœ ์ž์‹ ์„ ๊ณ„์†ํ•ด์„œ ์ถ”๊ฐ€
      }, 0);
    }

    // loop ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ
    loop();
  });
</script>

See the Pen MicroTask Queue์˜ ๋ฌดํ•œ ๋ฃจํ”„ 2 by barzz12 (@inpaSkyrim) on CodePen.

์ด๋ฒˆ์—๋Š” Promise ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•ด ์žฌ๊ท€ ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ ๋ฌดํ•œ ๋ฃจํ”„๋ฅผ ๊ตฌํ˜„ํ•ด ๋ณด์ž. ๋กœํ”„ ๋™์ž‘ ์ฝ”๋“œ ์ž์ฒด๋Š” ์œ„์˜ setTimeout๊ณผ ๋ณ„๋‹ค๋ฅธ ์ฐจ์ด๊ฐ€ ์—†๋‹ค. ๋‹ค๋งŒ ์ด ๋ฃจํ”„ ์ฝœ๋ฐฑ์ด Task Queue ๊ฐ€ ์•„๋‹Œ MicroTask Queue์— ๋“ค์–ด๊ฐ„๋‹ค๋Š” ์ฐจ์ด์ ์ด ์žˆ๋Š”๋ฐ, MicroTask Queue ๊ฐ€ ๋ฌดํ•œ ๋ฃจํ”„์— ๋น ์ง€๊ฒŒ ๋˜๋ฉด ์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€ ๋ณด์ž. (์˜ˆ๋น„ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ํ•˜๋‚˜ ์ค€๋น„ํ•ด์„œ ํ…Œ์ŠคํŠธํ•˜๊ธฐ๋ฅผ ๊ถŒ์žฅํ•œ๋‹ค)

<button id="btn">Click me</button>
<button id="btn2">๋ฌดํ•œ๋ฃจํ”„ ์‹œ์ž‘</button>

<div id="loopArea" style="border: 1px solid black; max-height: 150px; overflow-y: auto;"></div>

<script>
  // ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์ฝ˜์†”์— Clicked๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.
  document.getElementById("btn").addEventListener("click", () => {
    document.body.insertAdjacentHTML('beforeend', "<p>Clicked</p>");
  });

  document.getElementById("btn2").addEventListener("click", () => {
    // Promise ๊ฐ์ฒด๋Š” MicroTask Queue์— ์ฝœ๋ฐฑ์„ ์ถ”๊ฐ€
    function loop() {
      Promise.resolve().then(() => {
        document.getElementById("loopArea").append("Loop\n");
        loop(); // loop ํ•จ์ˆ˜๊ฐ€ Promise ๊ฐ์ฒด์˜ ์ฝœ๋ฐฑ์œผ๋กœ ์ž์‹ ์„ ๊ณ„์†ํ•ด์„œ ์ถ”๊ฐ€
      });
    }

    // loop ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ
    loop();
  });
</script>

See the Pen MicroTask Queue์˜ ๋ฌดํ•œ ๋ฃจํ”„ 3 by barzz12 (@inpaSkyrim) on CodePen.

์›น์‚ฌ์ดํŠธ๊ฐ€ ๋จนํ†ต์ด ๋˜์–ด ๋ฒ„๋ฆด ๊ฒƒ์ด๋‹ค. ๋˜‘๊ฐ™์€ ๋ฌดํ•œ ๋ฃจํ”„ ๋™์ž‘์ธ๋ฐ ํ•˜๋‚˜๋Š” ์›น์‚ฌ์ดํŠธ ๋™์ž‘์— ๋ฌธ์ œ๊ฐ€ ์—†์—ˆ๊ณ , ํ•˜๋‚˜๋Š” ์›น์‚ฌ์ดํŠธ ์ž์ฒด๊ฐ€ ๋ธ”๋ฝ์ด ๋˜์–ด๋ฒ„๋ ค ์–ด๋– ํ•œ ๋™์ž‘์„ ํ•  ์ˆ˜ ์—†๊ฒŒ ๋œ ๊ฒƒ์ด๋‹ค. ์™œ๋ƒํ•˜๋ฉด MicroTask Queue๊ฐ€ ๋น„์–ด์žˆ์ง€ ์•Š์œผ๋ฏ€๋กœ ๋‹ค๋ฅธ ๋งคํฌ๋กœํƒœ์Šคํฌ๋‚˜ ์ด๋ฒคํŠธ ์ฝœ๋ฐฑ์ด ์‹คํ–‰๋  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋ฌดํ•œ ๋ฃจํ”„ ์ฝ”๋“œ ๋•Œ๋ฌธ์— ๋Š์ž„์—†์ด MicroTask Queue์— ์ฝœ๋ฐฑ์ด ์ ์žฌ๋˜๊ฒŒ ๋˜๊ณ  ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ์ด๋“ค์„ ๋ธŒ๋ผ์šฐ์ € ํ™”๋ฉด ๋ Œ๋”๋ง์„ ํ•˜๊ธฐ์ „์— ์šฐ์„ ์œผ๋กœ ๋Š์ž„ ์—†์ด ์ฒ˜๋ฆฌ ๋˜ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๊ฒฐ๊ตญ ์‚ฌ์šฉ์ž ์ด๋ฒคํŠธ์— ๋ฐ˜์‘ํ•˜์ง€ ๋ชปํ•˜๊ณ , ํŽ˜์ด์ง€๊ฐ€ ๋ฉˆ์ถ”๊ฑฐ๋‚˜ ์‘๋‹ตํ•˜์ง€ ์•Š๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค. 

์ด ์˜ˆ์‹œ ์ฝ”๋“œ์˜ ์‚ฌ๋ก€๋Š” ์กฐ๊ธˆ ๊ทน๋‹จ์ ์ธ ์–ต์ง€ ์ฝ”๋“œ๋ผ ์ž˜ ์™€๋‹ฟ์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ํŒŒํŠธ์˜ ํ•ต์‹ฌ์€ ๋งŒ์ผ MicroTask Queue๋ฅผ ์‚ฌ์šฉํ•˜๋Š” Promise ์ฝ”๋“œ๋‚˜ Mutation Observer ์˜ ์ฝœ๋ฐฑ์—์„œ ๋ฌดํ•œ ๋ฃจํ”„ ๊นŒ์ง€๋Š” ์•„๋‹ˆ๋”๋ผ๋„ ์ง€๋‚˜์น˜๊ฒŒ MicroTask Queue์— ์ฝœ๋ฐฑ์„ ์ง€๋‚˜์น˜๊ฒŒ ์ ์žฌํ•˜๋Š” ์ž‘์—…์ด ์žˆ๋‹ค๋ฉด ์ด๋ฅผ ์กฐ์‹ฌํžˆ ๋‹ค๋ฃจ์–ด์•ผ ํ•œ๋‹ค๋Š” ์ ์ด๋‹ค.


Animation Frames

Animation Frames๋Š” ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ™”๋ฉด์„ ๋‹ค์‹œ ๊ทธ๋ฆด ๋•Œ ์‹คํ–‰๋˜๋Š” ํ•จ์ˆ˜๋“ค์„ ๋‹ด์•„๋‘๋Š” ๊ณณ์ด๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์›น ํŽ˜์ด์ง€์—์„œ ์›€์ง์ด๋Š” ๋™๊ทธ๋ผ๋ฏธ๋ฅผ ๊ทธ๋ฆฌ๊ณ  ์‹ถ๋‹ค๋ฉด, requestAnimationFrame์ด๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋™๊ทธ๋ผ๋ฏธ์˜ ์œ„์น˜๋ฅผ ๋ฐ”๊ฟ”์ฃผ๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋„ฃ์–ด์ค˜ Animation Frames์— ์ ์žฌ๋˜์–ด ์‹คํ–‰๋œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ™”๋ฉด์„ ๊ฐฑ์‹ ํ•  ๋•Œ๋งˆ๋‹ค ๋™๊ทธ๋ผ๋ฏธ์˜ ์œ„์น˜๊ฐ€ ๋ฐ”๋€Œ๋ฉด์„œ ์›€์ง์ด๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๊ฒŒ ๋œ๋‹ค.

// setTimeout() ํ•จ์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜์— ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ๋„ฃ์–ด์ฃผ๋“ฏ์ด requestAnimationFrame๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ด๋‹ค
requestAnimationFrame(function() {
    // ๋™๊ทธ๋ผ๋ฏธ์˜ ์š”์†Œ๋ฅผ ์ฐพ์•„์„œ ๋ณ€์ˆ˜์— ์ €์žฅ
    let circle = document.getElementById("circle");

    // ๋™๊ทธ๋ผ๋ฏธ์˜ ์Šคํƒ€์ผ์„ ๋ณ€๊ฒฝํ•˜์—ฌ ์œ„์น˜๋ฅผ ๋ฐ˜์˜
    circle.style.left = x + "px";
    circle.style.top = y + "px";
})

Animation Frames์˜ ์šฐ์„ ์ˆœ์œ„๋Š” ๋ธŒ๋ผ์šฐ์ €์— ๋”ฐ๋ผ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค. Task Queue์™€ Microtask Queue๊ฐ€ ๋ชจ๋‘ ์ฒ˜๋ฆฌ๋œ ํ›„์— ์‹คํ–‰๋  ์ˆ˜๋„ ์žˆ๊ณ , Task Queue์™€ Microtask Queue ์‚ฌ์ด์— ์‹คํ–‰๋  ์ˆ˜๋„ ์žˆ๋‹ค. ์ด๋Š” ์ด๋ฒคํŠธ ๋ฃจํ”„์˜ ๋ช…์„ธ๊ฐ€ ์—…๋ฐ์ดํŠธ ๋ Œ๋”๋ง ๋‹จ๊ณ„์—์„œ ์–ธ์ œ ์ฝœ๋ฐฑ์„ ํ˜ธ์ถœํ• ์ง€ ์ •ํ™•ํ•˜๊ฒŒ ์ •์˜ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

console.log("script start");

// task queue์— ์ ์žฌ
setTimeout(function () {
  console.log("setTimeout");
}, 0);

// microtask queue์— ์ ์žฌ
Promise.resolve()
  .then(function () {
    console.log("promise1");
  })
  .then(function () {
    // 8. microtask ์‹คํ–‰
    console.log("promise2");
  });

// AnimationFrame์— ์ ์žฌ
requestAnimationFrame(function () {
  console.log("animation");
});

console.log("script end");

Animation Frames

  1. "script start"๋ฅผ ์ถœ๋ ฅ
  2. setTimeout ํ•จ์ˆ˜๊ฐ€ Task Queue์— “setTimeout” ํƒœ์Šคํฌ๋ฅผ ์ถ”๊ฐ€
  3. Promise.resolve ํ•จ์ˆ˜๊ฐ€ MicroTask Queue์— “promise1” ํƒœ์Šคํฌ๋ฅผ ์ถ”๊ฐ€
  4. requestAnimationFrame ํ•จ์ˆ˜๊ฐ€ Animation Frames Queue์— “animation” ํƒœ์Šคํฌ๋ฅผ ์ถ”๊ฐ€
  5. "script end"๋ฅผ ์ถœ๋ ฅ
  6. "promise1"์„ ์ถœ๋ ฅ
  7. Promise.then ํ•จ์ˆ˜๊ฐ€ ๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ ํ์— “promise2” ํƒœ์Šคํฌ๋ฅผ ์ถ”๊ฐ€
  8. "promise2"๋ฅผ ์ถœ๋ ฅ
  9. "animation"์„ ์ถœ๋ ฅ
  10. "setTimeout"์„ ์ถœ๋ ฅ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ด๋ฒคํŠธ ๋ฃจํ”„ ์‹œ๊ฐํ™”

์ง์ ‘ ์ฝ”๋“œ๋ฅผ ์“ฐ๊ณ  ์กฐ์ž‘ํ•˜์—ฌ ์• ๋‹ˆ๋ฉ”์ด์…˜์œผ๋กœ ๋ณผ ์ˆ˜ ์žˆ๋Š” ์‹œ๊ฐํ™” ์‚ฌ์ดํŠธ๊ฐ€ ์žˆ์–ด ์†Œ๊ฐœํ•ด๋ณธ๋‹ค. ์ด๊ฒƒ์ €๊ฒƒ ์‹คํ—˜ํ•ด๋ณด๋ฉฐ ๋ธŒ๋ผ์šฐ์ € ๋‚ด๋ถ€์—์„œ ๋น„๋™๊ธฐ ๋™์ž‘์ด ์–ด๋– ํ•œ ์ˆœ์„œ๋กœ ์ผ์–ด๋‚˜๋Š”์ง€ ์•Œ์•„๋ณด์ž.

 

http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gdGltZXIoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ1lvdSBjbGlja2VkIHRoZSBidXR0b24hJyk7ICAgIAogICAgfSwgMjAwMCk7Cn0pOwoKY29uc29sZS5sb2coIkhpISIpOwoKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coIkNsaWNrIHRoZSBidXR0b24hIik7Cn0sIDUwMDApOwoKY29uc29sZS5sb2coIldlbGNvbWUgdG8gbG91cGUuIik7%21%21%21PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D

 

latentflip.com

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ด๋ฒคํŠธ ๋ฃจํ”„ ์‹œ๊ฐํ™”


# ์ฐธ๊ณ ์ž๋ฃŒ

[10๋ถ„ ํ…Œ์ฝ”ํ†ก] ๋ณ‘๋ฏผ์˜ ๋ธŒ๋ผ์šฐ์ €์˜ Event Loop

https://dev.to/lydiahallie/javascript-visualized-event-loop-3dif

https://dev.to/lydiahallie/javascript-visualized-promises-async-await-5gke

https://iamsjy17.github.io/javascript/2019/07/20/how-to-works-js.html

https://meetup.nhncloud.com/posts/89

https://sculove.github.io/post/javascriptflow/