What the heck is the event loop anyway? | Philip Roberts | JSConf EU - hochan222/Everything-in-JavaScript GitHub Wiki

๋™์˜์ƒ ๋ณด๊ธฐ

How does JavaScript even work?

v8?? chrome runtime??? ๋“ค์–ด๋Š” ๋ดค์ง€๋งŒ ์ž์„ธํžˆ๋Š” ๋ชจ๋ฅธ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋˜ ๋ฌผ์–ด๋ณธ๋‹ค.

What is Javascript?

A single-threaded, non-blocking, asynchronous, concurrent language. It have call stack, an event loop, a callback queue some other apis and stuff.

๋ผ๊ณ  ์ˆ˜๋„ ์—†์ด ๋“ค์–ด๋ดค์ง€๋งŒ ์—ฌ์ „ํžˆ ๊ทธ ์˜๋ฏธ๋ฅผ ์ •ํ™•ํžˆ ๋ชจ๋ฅธ๋‹ค.

V8์„ cloneํ•ด์„œ ์ฐพ์•„๋ณด์•˜๋”๋‹ˆ setTimeout ์ด๋‚˜ DOM, HTTP Request๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ฝ”๋“œ๋“ค์„ ์ฐพ์•„ ๋ณผ ์ˆ˜ ์—†์—ˆ๋‹ค.

๋‹ค์Œ์€ ๊ฐ„๋žตํ™”๋œ Javascript Runtime ๊ตฌ์กฐ์ด๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์‹ฑ๊ธ€ ์“ฐ๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์ด๋‹ค. ์‹ฑ๊ธ€ ์“ฐ๋ ˆ๋“œ ๋Ÿฐํƒ€์ž„์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋Š” ๋œป์ธ๋ฐ, ๊ฒฐ๊ตญ ํ•œ๋ฒˆ์— ํ•˜๋‚˜์˜ ์‹ฑ๊ธ€ ์ฝœ ์Šคํƒ๋งŒ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธํ•œ๋‹ค. (== ํ•˜๋‚˜์˜ ํ”„๋กœ๊ทธ๋žจ์€ ๋™์‹œ์— ํ•˜๋‚˜์˜ ์ฝ”๋“œ๋งŒ ์‹คํ–‰ ํ•  ์ˆ˜ ์žˆ๋‹ค.)

Call Stack์€ ์ž๋ฃŒ๊ตฌ์กฐ๋กœ ์‹คํ–‰๋˜๋Š” ์ˆœ์„œ๋ฅผ ๊ธฐ์–ตํ•˜๊ณ  ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์Šคํƒ์˜ ๊ฐ€์žฅ ์œ„์ชฝ์—์„œ ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ๊บผ๋‚ด๊ฒŒ ๋˜๋Š”๋ฐ ์ด๊ฒŒ ์ฝœ ์Šคํƒ์ด ํ•˜๋Š” ์ผ์˜ ์ „๋ถ€์ด๋‹ค.

์ด ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด

  1. ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ ์ž์ฒด๋ฅผ ์˜๋ฏธํ•˜๋Š” main ํ•จ์ˆ˜๋ฅผ ์Šคํƒ์— ์ง‘์–ด ๋„ฃ๊ฒŒ ๋œ๋‹ค.
  2. ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๊ฒŒ ๋œ๋‹ค.
  3. ๋งˆ์ง€๋ง‰์— printSquare(4)๋ฅผ ๋งŒ๋‚˜๊ณ  ํ•จ์ˆ˜ ํ˜ธ์ถœ์ด๋‹ˆ, ์Šคํƒ์— ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
  1. ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜๋“ค์„ stack์— ๋„ฃ๊ณ  ๋ฌด์—‡์ธ๊ฐ€ return ํ•  ๋•Œ๋งˆ๋‹ค ์Šคํƒ ๋งจ์œ„์—์žˆ๋Š”๊ฒƒ์„ ๊บผ๋‚ด๊ฒŒ ๋œ๋‹ค.
  2. printSquare๋Š” return์ด ์—†์ง€๋งŒ ์•”๋ฌต์ ์œผ๋กœ return ํ•œ๋‹ค.

๋งŒ์•ฝ ์œ„์˜ ๊ฒฝ์šฐ ์—๋Ÿฌ๊ฐ€ ๋‚œ๋‹ค๋ฉด ํฌ๋กฌ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ์—์„œ ์Šคํƒ์˜ ๊ผฌ๋ฆฌ๋ฅผ ๋ฌผ๋ฉด์„œ Oops!๋ฅผ ํ‘œ์‹œํ•  ๊ฒƒ์ด๋‹ค. ์ ์  ์˜ฌ๋ผ๊ฐ€๋‹ค๊ฐ€ ์ต๋ช…ํ•จ์ˆ˜(=mainํ•จ์ˆ˜)๊นŒ์ง€ ์˜ฌ๋ผ๊ฐ„๋‹ค!

blocking

๋ธ”๋กœํ‚น์˜ ์ •ํ™•ํ•œ ์ •์˜๋Š” ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ์ € ๋Š๋ฆฌ๊ฒŒ ๋™์ž‘ํ•˜๋Š” ์ฝ”๋“œ ์ผ ๋ฟ์ด๋‹ค.
console.log๋Š” ๋Š๋ฆฌ์ง€ ์•Š์ง€๋งŒ ์—ฌ๋Ÿฌ๋ฒˆ while๋ฌธ์œผ๋กœ ํ˜ธ์ถœ๋˜๋ฉด ๋Š๋ฆด๊ฒƒ์ด๋‹ค.
๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด๋‚˜ ์ด๋ฏธ์ง€ ํ”„๋กœ์„ธ์‹ฑ์€ ๋Š๋ฆฌ๋‹ค. ๋Š๋ฆฐ ๋™์ž‘์ด ์Šคํƒ์— ๋‚จ์•„์žˆ๋Š” ๊ฒƒ์„ ๋ณดํ†ต ๋ธ”๋กœํ‚น์ด๋ผ๊ณ  ํ•œ๋‹ค.

var foo = $.getSync('//foo.com');
var bar = $.getSync('//bar.com');
var qux = $.getSync('//qux.com');

console.log(foo);
console.log(bar);
console.log(qux);

์œ„ ์ฝ”๋“œ์™€ alert๋ฒ„ํŠผํ•˜๊ณ  ๋ฐ‘์— a href ํƒœ๊ทธ๊ฐ€ ์žˆ๋‹ค๊ณ  ์น˜์ž.
์šฐ๋ฆฌ๋Š” alert๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ๋„ ์œ„ ์š”์ฒญ ์‘๋‹ต์ด ๋๋‚  ๋•Œ ๊นŒ์ง€ alert ๋ฉ”์„ธ์ง€ ์ฐฝ์ด ๋œจ์ง€ ์•Š์„๊ฒƒ์ด๋‹ค.
๋˜ํ•œ, a href ํƒœ๊ทธ ๋˜ํ•œ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค.
๋ธŒ๋ผ์šฐ์ €๋Š” ๋ชจ๋“  ๋ฆฌํ€˜์ŠคํŠธ๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ ๊นŒ์ง€ ๋ฉˆ์ถฐ์žˆ์„ ๊ฒƒ์ด๋‹ค.
๋ฉˆ์ถฐ์žˆ๋Š”๋™์•ˆ ํ–‰๋™์„ ๊ธฐ์–ตํ•˜๊ณ  ์žˆ์ง€๋งŒ ๋ Œ๋”๋ง ํ•  ์ˆ˜ ์—†๋‹ค.

the solution?

asynchronous callbacks

๋ธŒ๋ผ์šฐ์ €๋‚˜ node.js์—๋Š” ๋ธ”๋กํ‚นํ•จ์ˆ˜๊ฐ€ ๊ฑฐ์˜ ์—†๋‹ค. ๋Œ€๋ถ€๋ถ„ ๋น„๋™๊ธฐ๋กœ ๋งŒ๋“ค์–ด์กŒ๋‹ค. ์–ด๋–ค ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๊ฒฐ๊ตญ ์ฝœ๋ฐฑ์„ ๋ฐ›๊ณ  ๋‚˜์ค‘์— ์‹คํ–‰ํ•˜๋Š”๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

settimeoutํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œํ‚ฌ ๋•Œ Call Stack์—๋Š” ์ถ”๊ฐ€๊ฐ€ ๋˜์ง€๋งŒ ์‚ฌ๋ผ์กŒ๋‹ค๊ฐ€ ์„ค์ •ํ•œ ์‹œ๊ฐ„ ์ดํ›„์— ๋‹ค์‹œ ์‹คํ–‰ ๋  ๊ฒƒ์ด๋‹ค.

Concurrency & the Event Loop

์ด๋ฒคํŠธ ๋ฃจํ”„์™€ ๋™์‹œ์„ฑ์ด ์ด ์—ญํ• ์„ ํ•œ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ๋™์‹œ์— ํ•œ๊ฐ€์ง€ ์ผ ๋ฐ–์— ํ•˜์ง€ ๋ชปํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ๊ฐ€ ์ด ์—ฌ๋Ÿฌ ์ผ๋“ค์„ ๋™์‹œ์— ํ•  ์ˆ˜ ์žˆ๋Š” ์ด์œ ๋Š” ๋ธŒ๋ผ์šฐ์ €๋Š” ๋‹จ์ˆœ ๋Ÿฐํƒ€์ž„ ์ด์ƒ์„ ์˜๋ฏธํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

Call Stack์—์„œ setTimeout์„ webapis์— ์ถ”๊ฐ€์‹œํ‚จ ํ›„ popํ•œ๋‹ค.

webapis๋Š” ๋ฐ”๋กœ Call Stack์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— task queue์— ์ง‘์–ด๋„ฃ์–ด์ง„๋‹ค.

์ด๋ฒคํŠธ ๋ฃจํ”„์— ๋‹ค๋‹ฌ์•˜๋‹ค.

์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” ์ด ์ „์ฒด ์‹œ์Šคํ…œ์—์„œ ์•„์ฃผ ๋‹จ์ˆœํ•œ ์ผ์„ ํ•˜๋Š” ์ž‘์€ ํŒŒํŠธ์ด๋‹ค.
์ด๋ฒคํŠธ ๋ฃจํ”„์˜ ์—ญํ• ์€ ์ฝœ ์Šคํƒ๊ณผ ํ…Œ์Šคํฌ ํ๋ฅผ ์ฃผ์‹œํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
์Šคํƒ์ด ๋น„์–ด์žˆ์œผ๋ฉด, ํ์˜ ์ฒซ๋ฒˆ์งธ ์ฝœ๋ฐฑ์„ ์Šคํƒ์— ์Œ“์•„ ํšจ๊ณผ์ ์œผ๋กœ ์‹คํ–‰ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.

์Šคํƒ์ด ๋น„์–ด์žˆ์„๋•Œ ์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” ์ฝœ๋ฐฑ์„ ์Šคํƒ์— ๋„ฃ์–ด์ค€๋‹ค.
Stack์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์˜์—ญ์ด๋‹ค. V8์—”์ง„์—์„œ ์ด์ œ console.log("there")์„ ์‹คํ–‰ํ•œ๋‹ค.

// Synchronous
[1, 2, 3, 4].forEach(function (i) {
  console.log('processing sync')
  delay();
});

// Asynchronous
function asyncForEach(array, cb) {
  array.forEach(function () {
    setTimeout(cb, 0);
  })
}

asyncForEach([1, 2, 3, 4], function (i) {
  console.log('processing async', i);
  delay();
})

๋‘๊ฐ€์ง€ ํ•จ์ˆ˜์— ์ฐจ์ด๋Š” ๋™๊ธฐ๋Š” Stack์˜์—ญ์—์„œ๋งŒ ์‹คํ–‰๋œ๋‹ค๋Š” ๊ฒƒ์ด๊ณ  ๋น„๋™๊ธฐ๋Š” Task Queue์— ์Œ“์˜€๋‹ค๊ฐ€ Stack์˜์—ญ์ด ๋น„์›Œ์ง€๋ฉด ์‹คํ–‰๋œ๋‹ค๋Š”๊ฒƒ์ด๋‹ค.

๋”ฐ๋ผ์„œ, ์•„์ฃผ ํฐ ๋ฐฐ์—ด ์ž‘์—…์„ ํ•  ๋•Œ, ๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋˜๋ฉด ๋‹ค๋ฅธ ์ž‘์—…์„ ์ง„ํ–‰ํ•˜์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ์–ด์„œ ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š”๊ฒƒ์ด ์ด์ƒ์ ์ด๋‹ค.

๋ Œ๋” ๋˜ํ•œ ๋งˆ์ฐฌ๊ฐ€์ง€์ธ๋ฐ ๋ Œ๋”๋ง๋„ ์Šคํƒ์ด ๋น„์›Œ์งˆ ๋•Œ ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€ ์‹คํ–‰๋œ๋‹ค.
๋‹ค๋ฅธ ์ ์ด๋ผ๋ฉด ๋ Œ๋”๋Š” ์ฝœ๋ฐฑ์— ๋น„ํ•ด ๋” ๋†’์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ–๋Š”๋‹ค.

์Šคํƒ์— ๋Š๋ฆฐ ์ž‘์—…์„ ๋„ฃ์–ด์„œ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ• ์ผ์„ ๋ชปํ•˜๊ฒŒ ํ•˜์ง€ ๋ง์•„๋ผ, ์œ ๋™์ ์ธ UI๋ฅผ ๋งŒ๋“ค์–ด๋ผ.

๊ทธ ์˜ˆ์‹œ๋กœ ์Šคํฌ๋กค ์ด๋ฒคํŠธ๋กค ๋“ฑ๋กํ•  ๋•Œ, ์—„์ฒญ๋‚œ ์ด๋ฒคํŠธ๋“ค์ด Callback Queue์— ์Œ“์ด๊ฒŒ ๋ ๊ฒƒ์ด๋‹ค.
์šฐ๋ฆฌ๋Š” ์ผ์ • ์ดˆ์˜ ํ…€์„ ๋‘๊ณ  ์‹คํ–‰ํ•˜๋ฏ€๋กœ์จ ์ด๋ฒคํŠธ ๋ฒ”๋žŒ์„ ๋ฐฉ์ง€ ํ•  ์ˆ˜ ์žˆ๋‹ค.