JavaScript 對(duì)引擎、運(yùn)行時(shí)、調(diào)用堆棧的概述理解
隨著JavaScript越來(lái)越流行,越來(lái)越多的團(tuán)隊(duì)廣泛的把JavaScript應(yīng)用到前端、后臺(tái)、hybrid 應(yīng)用、嵌入式等等領(lǐng)域。
這篇文章旨在深入挖掘JavaScript,以及向大家解釋JavaScript是如何工作的。我們通過(guò)了解它的底層構(gòu)建以及它是怎么發(fā)揮作用的,可以幫助我們寫(xiě)出更好的代碼與應(yīng)用。據(jù) GitHut 統(tǒng)計(jì)顯示,JavaScript 長(zhǎng)期占據(jù)GitHub中 Active Repositories 和 Total Pushes 的榜首,并且在其他的類別中也不會(huì)落后太多。
如果一個(gè)項(xiàng)目越來(lái)越依賴 JavaScript,這就意味著開(kāi)發(fā)人員必須利用這些語(yǔ)言和生態(tài)系統(tǒng)提供更深層次的核心內(nèi)容去構(gòu)建一個(gè)令人振奮的應(yīng)用。然而,事實(shí)證明,有很多的開(kāi)發(fā)者每天都在使用 JavaScript,但是卻不知道在底層 JavaScript 是怎么運(yùn)作的。
概述
幾乎每個(gè)人聽(tīng)說(shuō)過(guò) V8 引擎的概念,而且,大多數(shù)人都知道 JavaScript 是單線程的,或者是它是使用回調(diào)隊(duì)列的。
在這篇文章中,我們將詳細(xì)的介紹這些概念,并解釋 JavaScript 是怎么工作的。通過(guò)了解這些細(xì)節(jié),你就能利用這些提供的 API 來(lái)寫(xiě)出更好的,非阻塞的應(yīng)用來(lái)。如果你對(duì) JavaScript 比較陌生,那么這篇文章將幫助您理解為什么 JavaScript 相較于其他語(yǔ)言顯得如此“怪異”。如果您是一位經(jīng)驗(yàn)豐富的 JavaScript 開(kāi)發(fā)人員,希望它能給你帶來(lái)一些新的見(jiàn)解,說(shuō)明 JavaScript 的運(yùn)行時(shí),盡管你可能每天都會(huì)用到它。
JavaScript 引擎
JavaScript 引擎說(shuō)起來(lái)最流行的當(dāng)然是谷歌的 V8 引擎了, V8 引擎使用在 Chrome 以及 Node 中,下面有個(gè)簡(jiǎn)單的圖能說(shuō)明他們的關(guān)系:
這個(gè)引擎主要由兩部分組成:
- 內(nèi)存堆:這是內(nèi)存分配發(fā)生的地方
- 調(diào)用棧:這是你的代碼執(zhí)行時(shí)的地方
運(yùn)行時(shí)
有些瀏覽器的 API 經(jīng)常被使用到(比如說(shuō):setTimeout),但是,這些 API 卻不是引擎提供的。那么,他們是從哪兒來(lái)的呢?事實(shí)上這里面實(shí)際情況有點(diǎn)復(fù)雜。
所以說(shuō)我們還有很多引擎之外的 API,我們把這些稱為瀏覽器提供的 Web API,比如說(shuō) DOM、AJAX、setTimeout等等。
然后我們還擁有如此流行的事件循環(huán)和回調(diào)隊(duì)列。
調(diào)用棧
JavaScript 是一門單線程的語(yǔ)言,這意味著它只有一個(gè)調(diào)用棧,因此,它同一時(shí)間只能做一件事。
調(diào)用棧是一種數(shù)據(jù)結(jié)構(gòu),它記錄了我們?cè)诔绦蛑械奈恢?。如果我們運(yùn)行到一個(gè)函數(shù),它就會(huì)將其放置到棧頂。當(dāng)從這個(gè)函數(shù)返回的時(shí)候,就會(huì)將這個(gè)函數(shù)從棧頂彈出,這就是調(diào)用棧做的事情。
讓我們來(lái)看一看下面的例子:
function multiply(x, y) { return x * y; } function printSquare(x) { var s = multiply(x, x); console.log(s); } printSquare(5);
當(dāng)程序開(kāi)始執(zhí)行的時(shí)候,調(diào)用棧是空的,然后,步驟如下:
每一個(gè)進(jìn)入調(diào)用棧的都稱為_(kāi)_調(diào)用幀__。
這能清楚的知道當(dāng)異常發(fā)生的時(shí)候堆棧追蹤是怎么被構(gòu)造的,堆棧的狀態(tài)是如何的。讓我們看一下下面的代碼:
function foo() { throw new Error('SessionStack will help you resolve crashes :)'); } function bar() { foo(); } function start() { bar(); } start();
如果這發(fā)生在 Chrome 里(假設(shè)這段代碼實(shí)在一個(gè)名為 foo.js 的文件中),那么將會(huì)生成以下的堆棧追蹤:
"堆棧溢出",當(dāng)你達(dá)到調(diào)用棧最大的大小的時(shí)候就會(huì)發(fā)生這種情況,而且這相當(dāng)容易發(fā)生,特別是在你寫(xiě)遞歸的時(shí)候卻沒(méi)有全方位的測(cè)試它。我們來(lái)看看下面的代碼:
function foo() { foo(); } foo();
當(dāng)我們的引擎開(kāi)始執(zhí)行這段代碼的時(shí)候,它從 foo 函數(shù)開(kāi)始。然后這是個(gè)遞歸的函數(shù),并且在沒(méi)有任何的終止條件的情況下開(kāi)始調(diào)用自己。因此,每執(zhí)行一步,就會(huì)把這個(gè)相同的函數(shù)一次又一次地添加到調(diào)用堆棧中。然后它看起來(lái)就像是這樣的:
然后,在某一時(shí)刻,調(diào)用棧中的函數(shù)調(diào)用的數(shù)量超過(guò)了調(diào)用棧的實(shí)際大小,瀏覽器決定干掉它,拋出一個(gè)錯(cuò)誤,它看起來(lái)就像是這樣:
![]() |
在單個(gè)線程上運(yùn)行代碼很容易,因?yàn)槟悴槐靥幚碓诙嗑€程環(huán)境中出現(xiàn)的復(fù)雜場(chǎng)景——例如死鎖。但是在一個(gè)線程上運(yùn)行也非常有限制。由于 JavaScript 只有一個(gè)調(diào)用堆棧,當(dāng)某段代碼運(yùn)行變慢時(shí)會(huì)發(fā)生什么?
并發(fā)與事件循環(huán)
調(diào)用棧中的函數(shù)調(diào)用需要大量的時(shí)間來(lái)處理,那么這會(huì)發(fā)生什么情況呢?例如,假設(shè)你想在瀏覽器中使用 JavaScript 進(jìn)行一些復(fù)雜的圖片轉(zhuǎn)碼。
你可能會(huì)問(wèn)?這算什么問(wèn)題?事實(shí)上,問(wèn)題是當(dāng)調(diào)用棧有函數(shù)要執(zhí)行,瀏覽器就不能做任何事,它會(huì)被堵塞住。這意味著瀏覽器不能渲染,不能運(yùn)行其他的代碼,它被卡住了。如果你想在應(yīng)用里讓 UI 很流暢的話,這就會(huì)產(chǎn)生問(wèn)題。
而且這不是唯一的問(wèn)題,一旦你的瀏覽器開(kāi)始處理調(diào)用棧中的眾多任務(wù),它可能會(huì)停止響應(yīng)相當(dāng)長(zhǎng)一段時(shí)間。大多數(shù)瀏覽器都會(huì)這么做,報(bào)一個(gè)錯(cuò)誤,詢問(wèn)你是否想終止 web 頁(yè)面。
總結(jié)
以上所述是小編給大家介紹的JavaScript 對(duì)引擎、運(yùn)行時(shí)、調(diào)用堆棧的概述理解,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
JS實(shí)現(xiàn)css hover操作的方法示例
這篇文章主要介紹了JS實(shí)現(xiàn)css hover操作的方法,涉及javascript事件響應(yīng)及頁(yè)面元素css屬性動(dòng)態(tài)操作相關(guān)技巧,需要的朋友可以參考下2017-04-04js獲取上傳文件的絕對(duì)路徑實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇js獲取上傳文件的絕對(duì)路徑實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-08-08詳解MVC如何使用開(kāi)源分頁(yè)插件(shenniu.pager.js)
本文主要分享了shenniu.pager.js整個(gè)插件內(nèi)容,不多且清晰。具有很好的參考價(jià)值,需要的朋友一起來(lái)看下吧2016-12-12javascript setTimeout()傳遞函數(shù)參數(shù)(包括傳遞對(duì)象參數(shù))
由于需要,我要用到setTimeout()并且在里邊的函數(shù)參數(shù)傳遞一個(gè)參數(shù),就像這樣setTimeout("fun(參數(shù))", 1000)。但是以我這種寫(xiě)法,js會(huì)報(bào)錯(cuò),說(shuō)‘參數(shù)’未定義。2010-04-04javascript下動(dòng)態(tài)this與動(dòng)態(tài)綁定實(shí)例代碼
javascript是一門動(dòng)態(tài)語(yǔ)言,最明顯就是那個(gè)dynamic this。它一般都是作為函數(shù)調(diào)用者存在。在javascript,所有關(guān)系都可以作為對(duì)象的一個(gè)關(guān)聯(lián)數(shù)組元素而存在。2010-01-01js實(shí)現(xiàn)隨機(jī)點(diǎn)名器精簡(jiǎn)版
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)隨機(jī)點(diǎn)名器的精簡(jiǎn)版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06JS與Ajax Get和Post在使用上的區(qū)別實(shí)例詳解
這篇文章主要介紹了JS與Ajax Get和Post在使用上的區(qū)別實(shí)例詳解的相關(guān)資料,非常不錯(cuò)具有參考借鑒價(jià)值,需要的朋友可以參考下2016-06-06