摘要:如果我們進入一個函數,我們在堆棧的頂部。看看下面的代碼當引擎開始執行此代碼時,調用堆棧將為空。之后,步驟如下調用堆棧中的每個條目稱為堆棧幀。這正是拋出異常時構造堆棧跟蹤的方式當異常發生時,它基本上是調用堆棧的狀態。
隨著JavaScript越來越受歡迎,團隊正在利用這個技術棧在多個層次- 前端,后端,混合應用程序,嵌入式設備等等提供支持。
這篇文章旨在成為系列中第一個旨在深入挖掘JavaScript及其實際工作的系列文章:我們認為,通過了解JavaScript的構建方式以及它們如何協同構建,您將能夠編寫更好的代碼和 應用。
如GitHub統計所示,JavaScript在GitHub中的活躍庫數量和總推送數量位居前列。 在其他類別中也不會落后于很多。
(查看最新的GitHub語言統計信息)。
如果項目越來越依賴JavaScript,這意味著開發人員必須利用語言和生態系統提供的所有內容來更深入地了解內部內容,以便構建出令人驚艷的軟件。
事實證明,有很多開發人員每天都在使用JavaScript,但不知道什么會發生什么。
概覽幾乎所有人都已經聽說過V8引擎的概念,大多數人都知道JavaScript是單線程的,或者是使用回調隊列。
在這篇文章中,我們將詳細介紹所有這些概念,并解釋JavaScript如何運行。 通過了解這些細節,您將能夠編寫更好的非阻塞應用程序,正確利用提供的API。
如果您接觸JavaScript不久,此博文將幫助您了解為什么JavaScript與其他語言相比是如此“奇怪”。
如果您是一位經驗豐富的JavaScript開發人員,希望能夠為您提供一些新的見解,了解您每天使用的JavaScript運行時間是否真的有效。
JavaScript引擎JavaScript引擎的一個流行示例是Google的V8引擎。 例如,V8引擎在Chrome和Node.js中使用。 這是一個很簡單的視圖:
引擎由兩個主要組成部分組成:
內存堆 - 這是內存分配發生的地方
調用堆棧 - 這是您的代碼執行的堆棧幀
運行時瀏覽器中已經有幾個JavaScript開發人員使用的API(例如“setTimeout”)。 然而,引擎不提供這些API。
那么他們從哪里來?
事實證明,現實有點復雜。
所以,我們有引擎,但實際上還有更多。 我們有一些稱為Web API的東西,由瀏覽器提供,如DOM,AJAX,setTimeout等等。
還有就是非常時髦的事件循環和回調隊列。
調用堆棧JavaScript是單線程編程語言,這意味著它有一個單一的調用堆棧。 因此,它可以一次做一件事。
調用堆棧是一個數據結構,它基本上記錄了我們在程序中什么位置。 如果我們進入一個函數,我們在堆棧的頂部。 如果我們從一個函數返回,我們從堆棧的頂部彈出。 這就是堆棧可以做的。
我們來看一個例子。 看看下面的代碼:
function multiply(x, y) { return x * y; } function printSquare(x) { var s = multiply(x, x); console.log(s); } printSquare(5);
當引擎開始執行此代碼時,調用堆棧將為空。 之后,步驟如下:
調用堆棧中的每個條目稱為堆棧幀。
這正是拋出異常時構造堆棧跟蹤的方式 - 當異常發生時,它基本上是調用堆棧的狀態。 看看下面的代碼:
function foo() { throw new Error("SessionStack will help you resolve crashes :)"); } function bar() { foo(); } function start() { bar(); } start();
如果這是在Chrome中執行的(假設此代碼位于一個名為foo.js的文件中),則會產生以下堆棧跟蹤:
“Blowing the stack”? - 當您達到最大調用堆棧大小時,會發生這種情況。 這可能會很容易發生,特別是如果您在不經常地對代碼進行測試的情況下使用遞歸。 看看這個示例代碼:
function foo() { foo(); } foo();
當引擎開始執行這個代碼時,它首先調用函數“foo”。 然而,這個函數是遞歸的,并且開始調用自身而沒有任何終止條件。 所以在執行的每個步驟中,相同的功能被一次又一次地添加到調用堆棧中。 看起來像這樣:
然而,在某些時候,調用堆棧中的函數調用次數超過了調用堆棧的實際大小,并且瀏覽器決定采取行動,通過拋出一個錯誤,看起來像這樣:
在單個線程上運行代碼可能非常容易,因為您不必處理在多線程環境中出現的復雜場景,例如死鎖。
但是在單線程上運行也是非常有限的。 由于JavaScript有一個調用堆棧,當運行緩慢時會發生什么?
并發和事件循環當您在調用堆棧中進行函數調用需要大量時間才能處理時會發生什么? 例如,假設您想在瀏覽器中使用JavaScript進行一些復雜的圖像轉換。
你可能會問 - 為什么這甚至是一個問題? 問題是,雖然調用堆棧具有執行的功能,但瀏覽器實際上不能做任何事情 - 它被阻止。 這意味著瀏覽器無法渲染,它不能運行任何其他代碼,它只是卡住了。 如果您想要在應用中使用流暢的UI,這會產生問題。
這不是唯一的問題。 一旦您的瀏覽器開始處理Call Stack中的這么多任務,它可能會停止響應很長時間。 大多數瀏覽器通過提出錯誤來采取行動,詢問您是否要終止網頁。
現在,這不是最好的用戶體驗,是嗎?
那么,如何在不阻塞UI并使瀏覽器無響應的情況下執行繁重的代碼呢? 那么解決方案是異步回調。
這將在“JavaScript如何實際工作”教程的第2部分中更詳細地解釋:“V8引擎內有關如何編寫優化代碼的5個提示”。
翻譯自How JavaScript works: an overview of the engine, the runtime, and the call stack
關注我的公眾號,更多優質文章定時推送
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/91939.html
摘要:調用棧是一種單線程編程語言,這意味著它只有一個調用堆棧。調用棧是一種數據結構,它記錄了我們在程序中的位置。而且這不是唯一的問題,一旦你的瀏覽器開始處理調用棧中的眾多任務,它可能會停止響應相當長一段時間。 本文是旨在深入研究JavaScript及其實際工作原理的系列文章中的第一篇:我們認為通過了解JavaScript的構建塊以及它們是如何工作的,將能夠編寫更好的代碼和應用程序。我們還將分...
摘要:為了方便大家共同學習,整理了之前博客系列的文章,目前已整理是如何工作這個系列,可以請猛戳博客查看。以下列出該系列目錄,歡迎點個星星,我將更友動力整理理優質的文章,一起學習。 為了方便大家共同學習,整理了之前博客系列的文章,目前已整理 JavaScript 是如何工作這個系列,可以請猛戳GitHub博客查看。 以下列出該系列目錄,歡迎點個星星,我將更友動力整理理優質的文章,一起學習。 J...
摘要:調用堆棧是存放原始數據類型的地方除了函數調用之外。上一節中聲明變量后調用堆棧的粗略表示如下。解釋改變的正確方法是更改內存地址。在聲明時,將在調用堆棧上分配內存地址,該值是在堆上分配的內存地址。 這是專門探索 JavaScript 及其所構建的組件的系列文章的第 21 篇。 想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你! 如果你錯過了前面的章節,可以在這里找到它們:...
摘要:無論你使用的是解釋型語言還是編譯型語言,都有一個共同的部分將源代碼作為純文本解析為抽象語法樹的數據結構。和抽象語法樹相對的是具體語法樹,通常稱作分析樹。這是引入字節碼緩存的原因。 這是專門探索 JavaScript 及其所構建的組件的系列文章的第 14 篇。 想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你! 如果你錯過了前面的章節,可以在這里找到它們: JavaS...
摘要:調用棧是一種數據結構,它記錄了我們在程序中的位置。當從這個函數返回的時候,就會將這個函數從棧頂彈出,這就是調用棧做的事情。而且這不是唯一的問題,一旦你的瀏覽器開始處理調用棧中的眾多任務,它可能會停止響應相當長一段時間。 原文地址: https://blog.sessionstack.com... PS: 好久沒寫東西了,最近一直在準備寫一個自己的博客,最后一些技術方向已經敲定了,又可以...
閱讀 2314·2021-11-24 10:33
閱讀 1385·2019-08-30 15:43
閱讀 3275·2019-08-29 17:24
閱讀 3481·2019-08-29 14:21
閱讀 2219·2019-08-29 13:59
閱讀 1735·2019-08-29 11:12
閱讀 2811·2019-08-28 18:00
閱讀 1848·2019-08-26 12:17