摘要:調(diào)用棧是一種數(shù)據(jù)結(jié)構(gòu),它記錄了我們在程序中的位置。當(dāng)從這個(gè)函數(shù)返回的時(shí)候,就會將這個(gè)函數(shù)從棧頂彈出,這就是調(diào)用棧做的事情。而且這不是唯一的問題,一旦你的瀏覽器開始處理調(diào)用棧中的眾多任務(wù),它可能會停止響應(yīng)相當(dāng)長一段時(shí)間。
原文地址: https://blog.sessionstack.com...
PS: 好久沒寫東西了,最近一直在準(zhǔn)備寫一個(gè)自己的博客,最后一些技術(shù)方向已經(jīng)敲定了,又可以開心的學(xué)習(xí)了,node系列后續(xù)再開始。
??隨著JavaScript越來越流行,越來越多的團(tuán)隊(duì)廣泛的把JavaScript應(yīng)用到前端、后臺、hybrid 應(yīng)用、嵌入式等等領(lǐng)域。
??這篇文章旨在深入挖掘JavaScript,以及向大家解釋JavaScript是如何工作的。我們通過了解它的底層構(gòu)建以及它是怎么發(fā)揮作用的,可以幫助我們寫出更好的代碼與應(yīng)用。據(jù) GitHut 統(tǒng)計(jì)顯示,JavaScript 長期占據(jù)GitHub中 Active Repositories 和 Total Pushes 的榜首,并且在其他的類別中也不會落后太多。
??如果一個(gè)項(xiàng)目越來越依賴 JavaScript,這就意味著開發(fā)人員必須利用這些語言和生態(tài)系統(tǒng)提供更深層次的核心內(nèi)容去構(gòu)建一個(gè)令人振奮的應(yīng)用。然而,事實(shí)證明,有很多的開發(fā)者每天都在使用 JavaScript,但是卻不知道在底層 JavaScript 是怎么運(yùn)作的。
概述??幾乎每個(gè)人聽說過 V8 引擎的概念,而且,大多數(shù)人都知道 JavaScript 是單線程的,或者是它是使用回調(diào)隊(duì)列的。
??在這篇文章中,我們將詳細(xì)的介紹這些概念,并解釋 JavaScript 是怎么工作的。通過了解這些細(xì)節(jié),你就能利用這些提供的 API 來寫出更好的,非阻塞的應(yīng)用來。如果你對 JavaScript 比較陌生,那么這篇文章將幫助您理解為什么 JavaScript 相較于其他語言顯得如此“怪異”。如果您是一位經(jīng)驗(yàn)豐富的 JavaScript 開發(fā)人員,希望它能給你帶來一些新的見解,說明 JavaScript 的運(yùn)行時(shí),盡管你可能每天都會用到它。
JavaScript 引擎??JavaScript 引擎說起來最流行的當(dāng)然是谷歌的 V8 引擎了, V8 引擎使用在 Chrome 以及 Node 中,下面有個(gè)簡單的圖能說明他們的關(guān)系:
??這個(gè)引擎主要由兩部分組成:
內(nèi)存堆:這是內(nèi)存分配發(fā)生的地方
調(diào)用棧:這是你的代碼執(zhí)行時(shí)的地方
運(yùn)行時(shí)??有些瀏覽器的 API 經(jīng)常被使用到(比如說:setTimeout),但是,這些 API 卻不是引擎提供的。那么,他們是從哪兒來的呢?事實(shí)上這里面實(shí)際情況有點(diǎn)復(fù)雜。
??所以說我們還有很多引擎之外的 API,我們把這些稱為瀏覽器提供的 Web API,比如說 DOM、AJAX、setTimeout等等。
??然后我們還擁有如此流行的事件循環(huán)和回調(diào)隊(duì)列。
調(diào)用棧??JavaScript 是一門單線程的語言,這意味著它只有一個(gè)調(diào)用棧,因此,它同一時(shí)間只能做一件事。
??調(diào)用棧是一種數(shù)據(jù)結(jié)構(gòu),它記錄了我們在程序中的位置。如果我們運(yùn)行到一個(gè)函數(shù),它就會將其放置到棧頂。當(dāng)從這個(gè)函數(shù)返回的時(shí)候,就會將這個(gè)函數(shù)從棧頂彈出,這就是調(diào)用棧做的事情。
??讓我們來看一看下面的例子:
function multiply(x, y) { return x * y; } function printSquare(x) { var s = multiply(x, x); console.log(s); } printSquare(5);
??當(dāng)程序開始執(zhí)行的時(shí)候,調(diào)用棧是空的,然后,步驟如下:
??每一個(gè)進(jìn)入調(diào)用棧的都稱為__調(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 的文件中),那么將會生成以下的堆棧追蹤:
??"__堆棧溢出__",當(dāng)你達(dá)到調(diào)用棧最大的大小的時(shí)候就會發(fā)生這種情況,而且這相當(dāng)容易發(fā)生,特別是在你寫遞歸的時(shí)候卻沒有全方位的測試它。我們來看看下面的代碼:
function foo() { foo(); } foo();
??當(dāng)我們的引擎開始執(zhí)行這段代碼的時(shí)候,它從 foo 函數(shù)開始。然后這是個(gè)遞歸的函數(shù),并且在沒有任何的終止條件的情況下開始調(diào)用自己。因此,每執(zhí)行一步,就會把這個(gè)相同的函數(shù)一次又一次地添加到調(diào)用堆棧中。然后它看起來就像是這樣的:
??然后,在某一時(shí)刻,調(diào)用棧中的函數(shù)調(diào)用的數(shù)量超過了調(diào)用棧的實(shí)際大小,瀏覽器決定干掉它,拋出一個(gè)錯誤,它看起來就像是這樣:
??在單個(gè)線程上運(yùn)行代碼很容易,因?yàn)槟悴槐靥幚碓诙嗑€程環(huán)境中出現(xiàn)的復(fù)雜場景——例如死鎖。但是在一個(gè)線程上運(yùn)行也非常有限制。由于 JavaScript 只有一個(gè)調(diào)用堆棧,當(dāng)某段代碼運(yùn)行變慢時(shí)會發(fā)生什么?
并發(fā)與事件循環(huán)??調(diào)用棧中的函數(shù)調(diào)用需要大量的時(shí)間來處理,那么這會發(fā)生什么情況呢?例如,假設(shè)你想在瀏覽器中使用 JavaScript 進(jìn)行一些復(fù)雜的圖片轉(zhuǎn)碼。
??你可能會問?這算什么問題?事實(shí)上,問題是當(dāng)調(diào)用棧有函數(shù)要執(zhí)行,瀏覽器就不能做任何事,它會被堵塞住。這意味著瀏覽器不能渲染,不能運(yùn)行其他的代碼,它被卡住了。如果你想在應(yīng)用里讓 UI 很流暢的話,這就會產(chǎn)生問題。
??而且這不是唯一的問題,一旦你的瀏覽器開始處理調(diào)用棧中的眾多任務(wù),它可能會停止響應(yīng)相當(dāng)長一段時(shí)間。大多數(shù)瀏覽器都會這么做,報(bào)一個(gè)錯誤,詢問你是否想終止 web 頁面。
??這樣看來,這并不是最好的用戶體驗(yàn),不是嗎?
??那么,如何在不阻塞 UI 的情況下執(zhí)行復(fù)雜的代碼,讓瀏覽器不會不響應(yīng)?解決方案就是異步回調(diào)。這將在“ JavaScript 如何工作”教程的第2部分中詳細(xì)解釋:“在V8引擎中,如何編寫優(yōu)化代碼”。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/89712.html
摘要:本章會對語言引擎,運(yùn)行時(shí),調(diào)用棧做一個(gè)概述。調(diào)用棧只是一個(gè)單線程的編程語言,這意味著它只有一個(gè)調(diào)用棧。查看如下代碼當(dāng)引擎開始執(zhí)行這段代碼的時(shí)候,調(diào)用棧會被清空。之后,產(chǎn)生如下步驟調(diào)用棧中的每個(gè)入口被稱為堆棧結(jié)構(gòu)。 原文請查閱這里,本文采用知識共享署名 4.0 國際許可協(xié)議共享,BY Troland。 本系列持續(xù)更新中,Github 地址請查閱這里。 這是 JavaScript 工作原...
摘要:本章會對語言引擎,運(yùn)行時(shí),調(diào)用棧做一個(gè)概述。調(diào)用棧只是一個(gè)單線程的編程語言,這意味著它只有一個(gè)調(diào)用棧。查看如下代碼當(dāng)引擎開始執(zhí)行這段代碼的時(shí)候,調(diào)用棧會被清空。之后,產(chǎn)生如下步驟調(diào)用棧中的每個(gè)入口被稱為堆棧結(jié)構(gòu)。 原文請查閱這里,本文采用知識共享署名 4.0 國際許可協(xié)議共享,BY Troland。 本系列持續(xù)更新中,Github 地址請查閱這里。 這是 JavaScript 工作原...
摘要:調(diào)用棧是一種單線程編程語言,這意味著它只有一個(gè)調(diào)用堆棧。調(diào)用棧是一種數(shù)據(jù)結(jié)構(gòu),它記錄了我們在程序中的位置。而且這不是唯一的問題,一旦你的瀏覽器開始處理調(diào)用棧中的眾多任務(wù),它可能會停止響應(yīng)相當(dāng)長一段時(shí)間。 本文是旨在深入研究JavaScript及其實(shí)際工作原理的系列文章中的第一篇:我們認(rèn)為通過了解JavaScript的構(gòu)建塊以及它們是如何工作的,將能夠編寫更好的代碼和應(yīng)用程序。我們還將分...
摘要:如果我們進(jìn)入一個(gè)函數(shù),我們在堆棧的頂部??纯聪旅娴拇a當(dāng)引擎開始執(zhí)行此代碼時(shí),調(diào)用堆棧將為空。之后,步驟如下調(diào)用堆棧中的每個(gè)條目稱為堆棧幀。這正是拋出異常時(shí)構(gòu)造堆棧跟蹤的方式當(dāng)異常發(fā)生時(shí),它基本上是調(diào)用堆棧的狀態(tài)。 隨著JavaScript越來越受歡迎,團(tuán)隊(duì)正在利用這個(gè)技術(shù)棧在多個(gè)層次- 前端,后端,混合應(yīng)用程序,嵌入式設(shè)備等等提供支持。 這篇文章旨在成為系列中第一個(gè)旨在深入挖掘Jav...
摘要:本章將會深入谷歌引擎的內(nèi)部結(jié)構(gòu)。一個(gè)引擎可以用標(biāo)準(zhǔn)解釋程序或者即時(shí)編譯器來實(shí)現(xiàn),即時(shí)編譯器即以某種形式把解釋為字節(jié)碼。引擎的由來引擎是由谷歌開源并以語言編寫。注意到?jīng)]有使用中間字節(jié)碼來表示,這樣就不需要解釋器了。 原文請查閱這里,略有刪減。 本系列持續(xù)更新中,Github 地址請查閱這里。 這是 JavaScript 工作原理的第二章。 本章將會深入谷歌 V8 引擎的內(nèi)部結(jié)構(gòu)。我們也會...
閱讀 1245·2021-11-24 09:39
閱讀 390·2019-08-30 14:12
閱讀 2601·2019-08-30 13:10
閱讀 2446·2019-08-30 12:44
閱讀 970·2019-08-29 16:31
閱讀 856·2019-08-29 13:10
閱讀 2448·2019-08-27 10:57
閱讀 3161·2019-08-26 13:57