javascript
JS引擎、运行时与调用栈概述
概覽
幾乎所有人都已經(jīng)聽說了V8引擎的概念,大多數(shù)人都知道JavaScript是單線程運行的或者說是使用回調隊列的。
接下來,我們將詳細的講述這些概念,解釋JavaScript到底是怎樣運行的。當知道了這些細節(jié)后,你就能合理利用已有的API寫出更好的,非阻塞的應用。 如果你是JavaScript新手,這篇博客可以幫助你理解為什么相對于其他語言,JavaScript顯得如此奇怪。
如果你是比較有經(jīng)驗的JavaScript開發(fā)者,希望這篇博客可以讓你對你每天使用的JavaScript運行時到底是怎樣運行的有一些新的見解。
JavaScript引擎
一個流行的JavaScript引擎是谷歌的V8引擎。例如在Chrome和Node.js中使用的就是V8引擎。下圖是V8引擎一個非常簡單的預覽:
V8引擎由兩個主要組件所組成:
-
Memory Heap--內存分配區(qū)
-
Call Stack--代碼運行時棧
運行時
大部分JavaScript開發(fā)者都使用過瀏覽器的API(例如“setTimeout”)。然而這些API都不是由引擎提供的。 那么,它們來自哪里呢? 真實情況有點復雜。
所以除了引擎還有喝很多其他的東西。有瀏覽器提供的Web API,像DOM,AJAX,setTimeout等等。 然后還有非常有名的event loop和call queue。
調用棧
JavaScript是一門單線程的編程語言,也就是說它只有一個調用棧,因此它只能一次做一件事。
調用棧是一個記錄程序運行到哪里的數(shù)據(jù)結構。調用函數(shù)的時候,我們會把它放到棧的最頂部。從函數(shù)返回的時候,我們會把它從棧的最頂部彈出來。這就是調用棧做的所有的事情。
我們來看一個例子,看一下如下代碼:
function multiply(x, y) {return x * y; } function printSquare(x) {var s = multiply(x, x);console.log(s); } printSquare(5); 復制代碼當引擎開始執(zhí)行這段代碼的時候,調用棧是空的。接下來,每一步如下所示:
每次進入調用棧成為棧楨。 這就是當一個異常拋出時,棧的記錄是怎樣組成的,基本上就是當一個異常發(fā)生的時候調用棧的狀態(tài)。看一下如下代碼:
function foo() {throw new Error('SessionStack will help you resolve crashes :)'); } function bar() {foo(); } function start() {bar(); } start(); 復制代碼如果是運行在Chrome中(假定這段代碼在foo.js文件中),將會生成如下棧記錄:
“棧溢出”--這個發(fā)生在超過調用棧最大空間的時后。這非常容易發(fā)生,特別是當你使用遞歸但又沒有非常嚴格的測試你的代碼的時候。看一下如下代碼示例:
function foo() {foo(); } foo(); 復制代碼當引擎開始執(zhí)行這段代碼的時候,首先調用“foo”函數(shù),但是這個函數(shù)是遞歸的,開始調用自己并且沒有結束條件。所以每一步執(zhí)行,相同的函數(shù)都會一遍又一遍的加入到調用棧中,看上去就像這樣:
然而在某個時間點上調用棧中的函數(shù)調用數(shù)量將會超過調用棧的實際大小,此時瀏覽器決定采取行動,拋出一個錯誤,我們就會看到像下面這樣的提示:
在單線程上運行代碼是非常容易的,你不用處理在多線程中發(fā)生的復雜的場景--例如死鎖。
Concurrency & the Event Loop
在調用棧中存在需要花費很多時間的函數(shù)調用時會發(fā)生什么呢?例如,想象一下你需要在瀏覽器中利用JavaScript來做一些復雜的圖片轉換。
你可能會問--這有什么好問的?問題就是調用棧在執(zhí)行函數(shù)的時候,瀏覽器不能做其他的事--瀏覽器被阻塞了。這意味著瀏覽器將不能渲染,不能運行其他代碼,就是說被阻塞了。如果你想要一個體驗很好,運行流暢的應用,這將會是很大的問題。
而且還不止這一個問題。一旦你的瀏覽器在調用棧中處理很多任務,它將會在很長時間內得不到響應,大多數(shù)瀏覽器將會拋出一個錯誤來采取行動,詢問你是否要結束這個web頁面。
這不是最好的用戶體驗,不是嗎?
所以,我們怎樣才能在運行很重的代碼的時候,不阻塞UI,使瀏覽器不需要等待響應呢?解決方案就是異步回調。
我們將會在下一節(jié)詳細講述。
對V8引擎的內部機制感興趣的同學可以看這里。
本文翻譯自:blog.sessionstack.com/how-does-ja…
總結
以上是生活随笔為你收集整理的JS引擎、运行时与调用栈概述的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 常用数据库中间件汇总
- 下一篇: 如何优雅的处理异常?SpringBoot