字幕列表 影片播放
>> (Phillip Roberts) hello, come in and sit down.
(Phillip Roberts))大家好,請進、請坐
So for the last session before the afternoon break, we have Phillip Roberts who works at
所以在下午休息時間之前的最後一節時間 我們邀請到Phillip Roberts
Andea and is here from London ‑‑ Scotland.
他任職於&yet公司,並從倫敦...是蘇格蘭
Edinbrough.
愛丁堡過來的
‑‑ wow, ten second memory, he's going to talk about the vent loop.
哇,才一下就忘了 他接下來會來談談Event Loop
If everyone could give Phillip a big brownedder round of applause.
請大家給Phillip掌聲歡迎他
>> Phillip Roberts: Okay hello everyone, thanks for coming to the side track, it's awesome
Phillip Roberts: 大家好,謝謝大家前來這個小場次 能看到這裡有滿滿的人
to see it packed out in here.
感覺非常棒
Can everyone give me a stretch.
現在能請大家做個伸展動作嗎?
I needed to stretch, so I look less weird.
因為我需要伸展一下,這樣我看起來才不會奇怪
I want to talk about the event loop and what the heck is the event loop, as in the event
我想要談一下Event Loop(事件循環) JavaScript裡面的Event Loop
loop inside JavaScript.
Event Loop到底是什麼東西
So first up, as he said I work for AndYet which is an awesome little Dev shop in the
首先,我說過我任職於&yet公司 我們是間小型而出色的美國公司
US, look us up if you need help with real‑time stuff.
如果有人需要即時性事情的幫忙 歡迎查一下我們的資訊
That's what we're good at.
那是我們的專業
So, about 18 months ago--I'm a paid professional JavaScript developer--I thought to myself
所以呢,大約18個月之前,我是個JavaScript工程師 我在心中想著
how does, like JavaScript actually work?
JavaScript到底是怎麼樣運作的呢?
And I wasn't entirely sure.
我當時並不是完全肯定
I'd heard V8 as a term, chrome's Runtime didn't really know what that meant, what that did.
當時我有聽過V8引擎、chrome的Runtime這些詞 但不清楚是什麼意思,或是有什麼功能
I'd heard things like single threaded, you know obviously I'm using callbacks.
我聽過一些東西,像是Single Thread(單執行緒) 我很明顯是在用Callback(回調)
How do callbacks work?
Callback是怎麼運作的?
I started a journey of like reading and research and experimenting in the browser which basically
於是我開啟了一段閱讀、研究 和在瀏覽器上的實驗的過程
started like this.
一開始是長這樣子的
‑‑ I was kind of like JavaScript what are you.
我那時心裡有點在想:“JavaScript,你是什麼鬼啊?”
I'm a single threaded single concurrent language ‑‑ right.
然後它回我說:“我是個單執行緒的程式語言” ...好喔
yeah, cool, I have a call stack, an event loop, a callback queue, and some other APIs
好,我有一個Call stack(呼叫堆疊)、一個Event Loop(事件循環) 一個Callback queue(回調佇列),還有一些API
and stuff.
等等的東西
‑‑ rite.
好
I did not do a computer science degree.
我沒有念過電腦科學學位
I mean, these words, they're words, so I heard about V8 and the various Runtimes and different
我是說,這些名詞的意義我不懂,所以我聽過V8引擎 還有幾個Runtime函式,還有不同的瀏覽器
browsers so I looked to V8 do you have a call stack, an event loop, a callback queue, and
所以我看了V8引擎,問說:你有沒有呼叫堆疊 事件循環、回調佇列...
some other APIs and stuff, I have a call stack and a heap, I don't know what those other
還有其他API等等的...我有呼叫堆疊,還有堆積 我不知道其他的東西是什麼
things are, okay, interesting so basically 18 months passed.
好,很有意思...於是18個月基本上就過去了
And I think I get this.
然後我覺得我搞懂了
(Laughing) and so, this is what I want to share with you today.
(笑聲)所以,這就是我今天想和大家分享的內容
Hopefully this will be useful if you're relatively new to JavaScript, help you understand why
如果你是JavaScript的新手的話 希望這些對你有幫助,幫助你了解
JavaScript is so weird when you compare it to other languages you might used why callbacks
為何JavaScript和其他你可能用過的程式語言 相比這麼古怪,為什麼回調
are a thing, cause us hell but are required.
是重要的東西,造成我們一堆痛苦 但是又躲不掉
And if you're an experienced JavaScript developer hopefully give you some fresh insights how
如果你是一位經驗豐富的JavaScript開發人員 那我希望可以給你一些關於
the Runtime you're using works so you can think about it a little better.
Runtime是如何運行的新見解 讓你能夠多深入思考一下
So if we look at the JavaScript Runtime itself like V8 which is the Runtime inside Chrome.
所以,我們可以看一下JavaScript Runtime V8引擎就是Chrome中的Runtime
This is a simplified view of what JavaScript Runtime is.
這個是JavaScript Runtime的簡化示意圖
The heap, where memory allocation happens, and then there's the call stack, which is
Heap記憶體,就是進行記憶體分配的地方 然後是呼叫堆疊,這個是
where your stack frames are and all that kind of stuff, but, if you, like, clone the V8
堆疊框架,還有所有相關的東西所在的位置 不過,如果比如說你複製V8引擎的程式碼庫
code base and grep for things like setTimeout or DOM or HTTP request, they're not in there,
然後用grep抓取一些像是setTimeout 或是DOM或是HTTP請求的東西,那些並不在那裡
they don't exist in V8, which was a surprise to me.
那些並不在V8引擎裡 這件事讓我大吃一驚,對吧?
It's first thing you use when you start thinking about async stuff and it's not in the V8 source.
setTimeout有點像是用JavaScript、想到非同步時 會用的第一樣東西,而那竟然不在V8引擎裡
Hmm ... interesting.
嗯...很有意思
So, over this 18 months of discovery I come to realize this is really, this is really
因此,在經過這18個月的發現之中 我逐漸了解到這確實是
the bigger picture, this is what I'm hoping to get you on board with today and understand
更大的概念,這就是我今天希望 帶大家認識的東西,了解一下
what these pieces are, we have the V8 Runtime but then we have these things called web APIs
這些東西是什麼,我們有V8引擎的Runtime 但是我們也有叫做Web API的東西
which are extra things that the browser provides.
而Web API是瀏覽器所提供的額外的東西
DOM, AJAX, time out, things like that, we have this mythical event loop and the callback
像是DOM、AJAX、setTimeout之類的東西 然後我們還有神秘的Event Loop,以及...
queue.
callback queue(回調佇列)
I'm sure you've heard some of these terms before, but maybe you don't quite understand
我很確定大家都聽過一部分的專有名詞了 但也許並不是太理解
how these pieces pull together.
這些東西是如何拼湊在一起的
So, I'm going to start from the beginning, some of this will be new, to words might be
所以,我要從頭開始講起 有些字詞對於一部分人可能很陌生
new to people, other people will get this.
一部分人可能聽得懂
We're going to quickly move on from here, bear with me if this is obvious, I think for
不過我們要開始快速講下去 如果太簡單的話,請忍耐一下,但我認為
a lot of people it's not.
對大多數人來說並不簡單
So, JavaScript is a single threaded programming language, single threaded Runtime, it has
所以呢,JavaScript是一種單執行緒的程式語言 單執行緒的Runtime
a single call stack.
它有單執行緒的呼叫堆疊
And it can do one thing at a time, that's what a single thread means, the program can
它可以一次做一件事 那就是單執行緒的意思,程式一次
run one piece of code at a time.
可以跑一段程式碼
So, let's try and visualize that just to get our heads around what that mean, so if I have
所以,我們來試著將它視覺化 來幫助我們為了解它的意思,所以如果我有
some code like this on your left, we've got a few functions, a function multiplier which
一些左手邊的程式碼 這裡有一些函式,有乘法函式
multiplies two numbers, square which calls multiply with the same number twice, a function
能將兩個數字相乘 平方函式,把同一個數字乘以兩次
which prints the square of a number of calling square and then calling console.log and then
有個函式是如果我要平方功能,然後呼叫console.org 它就將一個數字的平方結果印出來
at the bottom of our file we actually run print square, this code all good?
然後在我們檔案的底下,我們執行了printSquare 這段程式大家都懂嗎?
Make sense?
合理嗎?
Cool.
好
So, if we run this, well, I should back up a step, so the call stack is basically ‑‑
所以,如果我們執行它,等等,我應該倒回一步 抱歉,所以Callstack基本上
it's a data structure which records basically where in the program we are, if we step into
是一種資料結構,它能夠記錄幾種情況下 我們在程式中的哪個位置,比如說進入
a function, we put something on to the stack, if we return from a function, we pop off the
一段函式、比如我們在stack(堆疊)上放某個東西 從函式回傳結果的時候、我們取下stack頂端的東西
top of the stack that's all the stack can do, ‑‑ so if you run this file, there's
那些就是stack能做的事情... 所以如果你執行這個檔案
kind of a main function, right, like the file itself, so, we push that on to the stack.
裡頭有個主函式,對吧,就像這個檔案本身 所以我們把這個放到堆疊上
Then we have some function definitions, they're just like defining the state of the world,
接著還有一些函式定義 就像是定義了整個世界的狀態
and finally we got to print square, right, so print square is a function call, so we
最後還有printSquare函式 printSquare是一種函式呼叫方式
push that on to the stack, and immediately inside print square, push on to the stack,
所以我們把它推到堆疊上 然後在printSquare裡面,推到堆疊上的
which calls multiply, now we have a return statement, we multiply A and B and we return,
再呼叫Multiplt,現在我們有一個return statement(回傳陳述) 我們會把A和B相乘,然後回傳
when we return we pop something off the stack, so, pop, multiplier of the stack, returning
回傳的時候,我們會把某個東西從stack上移除 所以,我們移除相乘指令,回到square
to square, return to print square, console.log, there's no return, it's implicit, because
回到printSquare、console.org 現在是printSquare、沒有回傳指令,這是隱含的
we got to the end of the function, and we're done so that's like a visualization of the
因為我們已經走到函式的盡頭,這樣就走完了 所以這就是呼叫堆疊的示意圖
call stalk, does that make sense?
這部分可以理解嗎?
(Yes, Phil) even if you haven't thought about the call stack before, you've come across
(可以,Phil)就算你以前沒有想到過呼叫堆疊 你也一定有碰過
it when you've been doing browser‑side development, so if we have code like this, a function baz
那就是當你在瀏覽器端做開發的時候 所以假設我們有個這樣的程式,一個名為baz的函式
which calls bar, which calls Foo, which throws an error if we run it in Chrome we see this.
呼叫bar函式,而bar函式又呼叫Foo函式,最後丟出錯誤訊息 如果在Chrome上執行,我們會在Dev Tools看到這個...未被捕捉的錯誤:Oops
And it prints the stack trace, right, the state of the stack when that error happened,
程式會印出堆疊追蹤記錄,對吧? 在錯誤發生時,堆疊的狀態
so, uncaught error oops Foo, bar, Baz, anonymous function, which is our main.
所以我們看到:未被捕捉的錯誤: Oops Foo、bar、Baz、匿名函式,也就是我們的主程式
Equally, if you've heard the term like blowing the stack, this is an example of that.
同樣地,如果你有聽過一些像是堆疊爆炸 的名詞的話,這就是其中一個例子
Have a function foo which calls Foo , so what's going to happen ? We have a function main
foo函式呼叫foo函式的話,會怎麼樣? 這個嘛...我們跑主程式
which calls foo which calls foo, which calls foo, which calls foo, and ultimately chrome
呼叫foo函式,它再去呼叫foo函式 然後再呼叫foo函式,然後再呼叫foo函式,到最後chrome會說
says, you probably didn't mean to call foo 16,000 times recursively, I'll just kill things
你可能不是真的要重複呼叫foo函式一萬六千次 所以我會幫你中止一些
for you and you can figure out where your bug lies, right.
然後你就能釐清bug在哪裡了,對吧
So although I may be representing a new side of the call stack you have some sense of it
雖然我可能是在呈現呼叫堆疊的新的一面 你們可能多少已經在
in your development practice already.
開發的實作過程中多少了解一些了
So, the big question then comes is like what happens when things are slow?
所以,接著浮現的大哉問是 程式執行速度緩慢時會怎麼樣?
So, we talk about blocking and blocking behavior and blocking, there's no strict definition
我們會講到“阻塞”,還有阻塞的行為 阻塞其實沒有一個嚴格的定義
of what is and didn't blocking, really it's just code that's slow.
來說明什麼是阻塞、又什麼不是 它其實只是一段很慢的程式
So console.log isn't slow, doing a while loop from one to ten billion is slow, network requests
所以說console.org並不慢 執行一段一到一百億的while迴圈有點慢
are slow.
網路請求很慢
Image requests are slow.
圖片請求很慢
Things which are slow and on that stack are what are blocking means.
跑起來很慢、同時又在該堆疊上的東西 就是阻塞的意思
So heres a little example, so let's say we have, this is like a fake bit of code, getSynchronous,
這裡有個小例子,假設我們 弄一串假的程式碼:getSynchronous
right, like jQuery is like, AJAX request.
就好比jQuery...AJAX請求
What would happen if those were synchronous requests, forget what we know about async
如果這些是同步請求的話,會怎麼樣? 先忘掉非同步回調這件事
callbacks they're synchronous.
都先當作同步就好
If we go through it like we have, we call getSync and then we wait, because then we're
如果瀏覽一下我們走過了哪些東西 我們呼叫了getSync,然後我們等了一下,因為後來
doing network request, network is relative to computers, are slow, hopefully that network
我們在做網路請求 網路相對於電腦是很慢的,希望那段網路請求
requests completes, we can move on, wait, move on.
已經完成了,然後我們就能繼續跑... 等待、繼續跑...
Wait, and, I mean, this network request might never finish, so ... yeah, I guess I'll go
等待,然後,這段網路請求可能永遠不會跑完 所以...我想我不如
home.
回家好了
Finally those three, you know blocking behaviors complete and we can clear the stack, right.
最後那三個,blocking(阻塞)行為都已經完成 然後我們就能清除stack了,對吧?
So in a programming language is single threaded you're not using threads like say Ruby, that's
所以在一個單執行緒的程式語言中 不能像Ruby般使用多個執行緒
what happens, right, we make a network request, we have to just wait till it's done, because
就是那樣子,對吧,我們做了一個網路請求 我們只能等到它跑完為止
we have no way of handling that.
因為我們沒有處理這種情況的方法
Why is this actually a problem?
而這點為什麼是個問題呢?
The problem is because we're running code in browsers.
它之所以為問題 是因為我們是在瀏覽器裡執行程式的
So, let's you ‑‑ here we go, okay.
我們來...這裡,好
So this is just, this is Chrome, this is the code I just ran.
這個是Chrome,這裡是我剛剛跑過的程式
Browsers don't give us ‑‑ well they do give us synchronous AJAX request, I'm faking
瀏覽器不會給...噢,它其實會給我們 同步AJAX請求,我現在用一個大while迴圈
this out with a big while loop, because it's synchronous, I basically while loop for five
來假裝做到這件事,因為while 迴圈是同步的 我基本上會在繼續跑下去之前
seconds before continuing, so if I open up the console here.
先做五秒的while迴圈,所以如果我在這裡打開console
We can see what happens, so with request foo.com, why this is happening, I can't do anything,
我們就能看到發生了什麼事,所以我們對foo.com 提出請求,所以我們會想:怎麼會這樣?我什麼都做不了
right, even the run button hasn't finished rerendering the fact that I clicked it.
就算是“執行”按鈕 即使我剛剛按過也沒未rerender(重新渲染)完成
The browser is blocked, it's stuck, it can't do anything until those requests complete.
因為瀏覽器這時候被阻塞了,卡住了 直到請求都完成之前,它什麼都做不了
And then all hell breaks loose because I did some stuff,it figured that out I'd done it,
然後整個死結都打開了 因為我做了一些事,它發現我已經完成了
it couldn't actually render it.
它只是不能呈現結果
Couldn't do anything.
什麼都不能做
That's because if that call stack has things on it, and here it's got these yeah, it's
這是因為如果那段Call Stack上有東西的話 而這邊有...對...
still going.
它還在跑
We've got the synchronous request, the browser can't do anything else.
我們現在有同步請求 那瀏覽器其他事就做不了了
It can't render, it can't run any other code, it's stuck.
它無法顯示畫面、無法跑其他程式碼,都卡住了
Not ideal, right if we want people to have nice fluid UIs, we can't block the stack.
情況並不理想,對吧?如果我們希望人們 能看到流暢的 UI,我們就不能阻塞Stack
So, how do we handle this?
那我們要怎麼處理呢?
Well the simplest solution we're provided with is asynchronous callbacks, there's almost
這個嘛...我們所能用到的 最簡單的解法就是Async Callback(非同步回調)
no blocking functions in the browser, equally in node, they're all made asynchronous, which
瀏覽器中幾乎沒有Blocking(阻塞式)函式 在Node裡也是一樣,都是Async(非同步)的
basically means we run some code, give it a callback, and run that later, if you've
這基本上表示我們執行一些程式碼 給它回調,然後再執行,如果你已經
seen JavaScript you've seen asynchronous callbacks, what does this actually look like.
看過JavaScript,你就有看過非同步回調 它實際上是什麼樣的呢?
Simple example to remind people where we're at.
這裡有個簡單的例子 來提醒大家我們的問題在哪
Code like this, console.log hi.
像這樣的程式碼,console.log('Hi')
Write, we run the setTimeout, but that queue's the console log for future so we skip on to
我們執行setTimeout函式,但是那段佇列 不知為何是之後會出現的console.log,所以我們直接
JSConf and then five seconds later we log "there" right, make sense?
跳到JSConfEU,然後五秒鐘後 我們就紀錄了“there”,對嗎?
Happy.
行嗎?
Basically that's setTimeout is doing something.
基本上,那個setTimeout函式正在做事
So, asynchronous callbacks with regards to the stacks we saw before ... how does this
所以,我們之前看過的堆疊的 這一方面的非同步回調來說...是怎麼
work?
運作的呢?
Let's run the code.
那麼,我們就來跑程式吧
Console.log hi. setTimeout.
console.log('Hi')、setTimeout函式 好,接下來會怎麼樣?
We know it doesn't run immediately, we know it's going to run in five seconds time, we
我們都知道它沒有立刻執行 我們知道它要五秒鐘後才會跑
can't push it on to the stack, somehow it just disappears, we don't have like a way
我們無法把它推到堆疊上 不知為何地它就消失了,我們還沒有方法
of describing this yet, but we'll come to it.
去描述這件事,但是等一下會再講回來
We log JSConfEU, clear, five seconds later somehow magically "there" appears on the stack.
我們打印JSConfEU、清除 五秒鐘後,不知為何,“there”就神奇地出現在Stack上了。
How does that happen?
這是怎麼回事?
And that's ‑‑ this is basically where the event loop comes in on concurrency.
這基本上就是是事件循環 在並發執行上會發揮作用的地方
Right, so I've been kind of partially lying do you and telling you that JavaScript can
好,所以我一直算是沒講出完整的事實 告訴你們JavaScript只能
only do one thing at one time.
一次做一件事情
That's true the JavaScript Runtime can only do one thing at one time.
沒有錯,JavaScript Runtime 一次只能做一件事
It can't make an AJAX request while you're doing other code.
你在進行其他程式的時候 它就無法做出AJAX的請求