整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          JavaScript:高級-解析與執行過程

          JavaScript:高級-解析與執行過程

          JavaScript是一種描述型的腳本語言,是一種解析語言,由瀏覽器動態解析,不同類型的瀏覽器、不同版本的瀏覽器對于JavaScript的解析有著微小的差別,不同瀏覽器的JavaScript解析引擎效率也有差異。

          JavaScript的執行過程分為兩大部分:

          • 第一部分:解析過程,也稱為預編譯期。主要工作就是對于JavaScript的代碼中聲明的所有變量和函數進行預處理。需要注意的是,在此進行處理的僅是聲明函數,而對于變量的處理僅是聲明,并開辟出一塊內存空間,不進行賦值操作;
          • 第二部分:執行過程。在執行過程中,瀏覽器的JavaScript引擎對于每個代碼塊進行順序執行。如果有外部引用的JavaScript,且JavaScript相互關聯,此時就要注意,不同JavaScript的引入順序。如果聲明代碼塊在調用代碼塊后調用,則將不會達到預期的效果。

          總的來說,JavaScript的執行分為兩部分:解析過程和執行過程。解析時按照代碼塊,一段一段進行解析,執行時按照代碼塊順序逐行執行,解析一個代碼塊,執行一個代碼塊。

          因為是解釋型語言,所以JavaScript如果在解析過程中有錯誤,則不會提示,也可以理解為JavaScript不會出現編譯錯誤,但如果出現了運行時錯誤,出現錯誤以下的所有JavaScript代碼將不會繼續執行。

          全局預處理階段

          預處理:創建一個詞法環境(LexicalEnvironment,簡寫為LE),掃描JavaScript中用聲明的方式聲明的函數,用var定義的變量并將它們加到預處理階段的詞法環境中去。

          預處理階段先讀取代碼塊,不是一行一行的解析執行定義的方法和用var定義的變量,會放到一個(不同的環境,會有對應的詞法環境)詞法環境環境中。

           var a=1;    // 用var定義的變量,已賦值
           var b;        // 用var定義的變量,未賦值
           c=3;        // 未定義的變量,直接賦值
           
           // 用聲明的方式聲明的函數
           function d(){
             console.log('hello');
           }
           
           // 函數表達式
           var e=function() {
             console.log('world');
           }

          詞法環境:

           LE {  // 此時的LE相當于window
             a: undefined
             b: undefined
             d: 函數引用
             e: undefined
           }

          預處理的函數必須是JavaScript中用聲明的方式聲明的函數,不是函數表達式。

          示例:

           d();
           e();
           
           // 用聲明的方式聲明的函數
           function d(){
             console.log('hello');
           }
           
           // 函數表達式
           var e=function() {
             console.log('world');
           }

          執行結果:

           hello
           
           TypeError: e is not a function

          命名沖突

          函數優先原則:在既有函數聲明又有變量聲明的時候,函數聲明的權重高于變量聲明,所以最終結果往往是指向函數的引用。

          示例 1:

           console.log(f);
           
           var f=1;
           
           function f() {
             console.log('func');
           }

          結果:

           [Function: f]

          示例 2:

           console.log(f);
           
           function f() {
             console.log('func');
           }
           
           var f=1;

          結果:

           [Function: f]

          執行階段

           console.log(a); //  undefined
           console.log(b); //  TypeError: b is not a function
           console.log(c); //  [Function: f]
           console.log(d); //  undefined
           
           var a=1;
           b=2;
           console.log(b); // 2
           function c(){
             console.log('c');
           }
           
           var d=function(){
             console.log('d');
           }
           
           console.log(d); //  [Function: f]
           

          詞法環境:

           LE {
             a: undefined
             c: [Function: f]
             d: undefined
           }

          函數沖突原則

          1. 處理函數聲明有沖突時,會覆蓋;
          2. 處理變量聲明有沖突時,會忽略。以傳入參數的值為準。

          預處理階段傳輸參數值一一對應

           function func(a, b) {
             console.log(a);
             console.log(b);
             
             var b=100;
             function a{}
           }
           
           func(1, 2);

          詞法環境:

           LE {
             b: 2
             a: 指向函數的引用
             arguments: 2  // 調用函數時實際調用的參數個數
           }

          運行結果:

           [Function: f]
           2

          沒有用var聲明的變量,會變成最外部LE的成員,即全局變量:

          用代碼分割、延遲加載、使用 Web Workers、壓縮文件和異步加載等技術提升您的 JavaScript 技能。

          譯自 How To Master JavaScript Performance Optimization,作者 Alexander T Williams。

          JavaScript 是現代 Web 應用程序的基石,為從動態內容到交互式功能的一切提供支持。然而,隨著應用程序變得越來越復雜,確保 JavaScript 能夠高效運行變得至關重要。

          隨著用戶對更快、更具響應性的應用程序的需求不斷增長,開發人員必須優先考慮 JavaScript 優化以滿足這些期望。從減少加載時間到提高交互性,優化您的 JavaScript 可以顯著提高 Web 應用程序的整體性能。

          為什么優化 JavaScript 的性能

          正確理解網站的性能是優化 JavaScript 代碼的第一步。

          考慮到這一點,衡量您的網站或應用程序的性能至關重要,因為它可以幫助您識別影響下載時間、渲染速度和整體用戶體驗的瓶頸。

          如果沒有對性能進行適當的衡量,您可能會浪費時間應用優化,而這些優化并不能解決您的網站所面臨的實際問題。

          分析性能數據

          有幾種工具可以幫助您有效地衡量性能。內置的瀏覽器工具,例如 Chrome DevTools,提供關于網絡活動、加載時間和 CPU 使用率的全面而有價值的見解。

          收集完性能數據后,下一步是確定哪些優化是必要的。

          這些工具可以讓您看到頁面中哪些部分加載時間最長,以及哪些腳本可能會減慢網站速度。除此之外,性能 API 還可以提供更復雜的數據,用于深入分析。

          收集完性能數據后,下一步是確定哪些優化是必要的。并非每種技術都適合每個項目,因此根據您網站的具體需求進行優先排序非常重要。

          例如,如果您的分析表明事件處理程序會導致延遲,您可以專注于改進事件管理。類似地,如果大型 JavaScript 文件會減慢加載時間,縮小和異步加載可能是正確的解決方案。

          此外,它還可以幫助您遵守 GDPR,或與您的網站或應用程序相關的歐盟、美國或其他地方的任何數據保護法規。優化您的 JavaScript 有助于提高性能,同時確保您的數據處理實踐符合標準。

          正確管理的代碼可以幫助最大限度地減少不必要數據的收集,從而簡化嘗試遵守和遵循重要監管要求的過程。

          優化 JavaScript 性能的挑戰

          我們都經歷過:如果您的代碼沒有得到妥善管理,JavaScript 有時會成為一個真正的頭痛問題。

          您可能遇到的一些常見問題包括質量較差的事件處理,這會導致深層調用堆棧和更慢的性能。無序的代碼是另一個大問題,會導致資源分配效率低下,并使瀏覽器更難快速執行腳本。

          代碼拆分允許您將 JavaScript 代碼分解成更小、更易于管理的塊。

          然后是過度依賴的問題,這會減慢應用程序的速度,通常會顯著減慢速度,尤其是對于帶寬有限的移動用戶而言——而且不要忘記,低效的迭代會不必要地拖延處理時間。

          理解和實現代碼拆分

          代碼拆分允許您將 JavaScript 代碼分解成更小、更易于管理的塊——這在您的應用程序變得越來越復雜時至關重要,有助于減少加載時間并提高用戶的初始渲染速度。

          那么,如何進行代碼拆分呢?一種常用的方法是使用動態導入,它允許您僅在需要時加載 JavaScript 模塊,而不是一次性將整個應用程序加載到用戶身上。這就像只為周末旅行打包必需品,而不是打包整個衣櫥。

          根據最近的調查統計,48.9% 的開發人員已采用動態導入按需加載模塊,45.7% 的開發人員正在使用服務工作者 來增強離線用戶體驗。

          同樣,對于 JS 庫也是如此,允許進行各種應用內操作,例如在 React 應用中查看文檔,動態在實時分析儀表板中渲染圖表,或加載交互式地圖以用于基于位置的服務。然后是 webpack,一個工具,一旦你掌握了它,就會感覺有點像魔法;它可以自動將你的代碼拆分成更小的塊,按需加載它們。

          如何實現代碼拆分

          1. 動態導入: 使用import() 函數在需要時加載模塊。例如:
          import('./module.js').then(module=> {
            module.doSomething();
          });
          1. Webpack 配置: 配置 webpack 使用SplitChunksPlugin 和optimization.splitChunksoptions 自動將代碼拆分成更小的塊。
          2. React.lazy: 在 React 應用中,使用React.lazy 進行組件級代碼拆分:
          const MyComponent=React.lazy(()=> import('./MyComponent'));

          實現延遲加載以提高性能

          延遲加載是一種很棒的技術,可以通過延遲加載非必要資源來提高 Web 應用的性能,直到它們真正需要時才加載。

          簡而言之,延遲加載允許這些元素僅在進入用戶的視野時加載,而不是讓用戶等待每個圖像、視頻或媒體文件預先加載。

          延遲加載最常見的用例包括圖像、視頻和其他媒體密集型內容等元素。使用延遲加載可以大幅減少初始加載時間,從而增強網站或應用的整體用戶體驗。

          實現延遲加載的一種流行方法是通過 Intersection Observer API。這個特定的 API 允許你檢測元素何時進入或退出視窗,因此你可以在內容即將對用戶可見時才加載它。它效率高且設置起來相對容易。

          如何實現延遲加載

          1. Intersection Observer API: 檢測元素何時進入視窗并動態加載內容:
          const observer=new IntersectionObserver((entries)=> {
            entries.forEach(entry=> {
              if (entry.isIntersecting) {
                loadImage(entry.target);
                observer.unobserve(entry.target);
              }
            });
          });
          
          document.querySelectorAll('img[data-src]').forEach(img=> observer.observe(img));
          1. 對于 React 開發人員,React.lazy 函數是延遲加載組件的強大工具。使用React.lazy,你可以在組件級別拆分代碼,以便僅在需要時加載應用的必要部分。

          利用 Web Workers 卸載繁重的計算

          Web Workers 是現代 Web 開發中的一項強大功能,旨在幫助處理繁重的計算,而不會減慢用戶界面。

          Web Workers 從主線程卸載密集型任務,通過在后臺線程中運行腳本,提供流暢且響應迅速的用戶體驗。

          Web Workers 通過啟用并行執行來顯著提高性能;因此,當主線程處理用戶交互和渲染時,Web Workers 負責后臺的資源密集型操作,例如數據處理和計算。這可以防止 UI 由于長時間運行的腳本而變得無響應。

          使用 Web Workers 的一些更實際的示例包括卸載基本數據處理任務。例如,當處理需要排序、過濾或復雜計算的大型數據集時,Web Worker 可以管理這些操作,而不會凍結主 UI 線程。

          如何利用 Web Workers

          1. 創建 Web Worker: 為工作者創建一個單獨的 JavaScript 文件:
          // worker.js
          self.onmessage=(e)=> {
            const result=computeHeavyTask(e.data);
            postMessage(result);
          };
          1. 使用 Web Worker: 從主線程實例化并與工作者通信:
          const worker=new Worker('worker.js');
          
          worker.onmessage=(e)=> {
            console.log('Result from worker:', e.data);
          };
          
          worker.postMessage(data);

          JavaScript 優化的其他技術

          優化 JavaScript 不僅僅是代碼分割和延遲加載,還有其他一些技術可以顯著提高應用程序的性能。

          異步加載允許腳本與其他資源并行獲取。

          一種重要的方法是 壓縮和壓縮 JavaScript 文件,這涉及從代碼中刪除不必要的字符和空格,而不會改變其功能。像 UglifyJS 這樣的工具可以幫助完成此過程,使用 gzip 或 Brotli 壓縮可以進一步減小文件大小,從而加快加載時間。

          另一方面,異步加載允許腳本 與其他資源并行獲取,防止它們阻塞頁面的渲染。HTML 中的 async 屬性通常用于此目的。

          使用 defer 屬性延遲腳本,確保 代碼在初始 HTML 解析后執行,這提高了用戶與網站交互的速度。

          利用 HTTP/2 和 JavaScript CDN 可以進一步提高網站或應用程序的性能。

          HTTP/2 引入了多路復用等功能,允許多個請求同時通過單個連接發送,從而減少延遲。使用 內容交付網絡 (CDN) 為您的 JavaScript 文件提供服務 可以保證它們從更靠近用戶的位置提供服務,從而加快交付速度。

          提升您的 JavaScript 水平

          代碼分割、延遲加載、使用 Web Workers、壓縮文件和利用異步加載等技術并不完全是秘密,但開發人員并沒有充分利用它們——遠非如此。

          每種方法都可以提高應用程序的速度和響應能力,將它們納入開發工作流程將提供更流暢的用戶體驗,并使您的應用程序保持領先地位。

          了執行Javascript,需要在HTML文件內以特定的方式書寫JavaScript的代碼,JavaScript的書寫方法有多種,其執行的流程也各不相同:

          1 <script>標簽嵌入

          此種嵌入方法無法操作<script>之后的DOM元素。因為<script>之后的DOM元素還未構造,因此在<script>標簽內就無法取得位于其后的DOM元素。

          2 讀取外部JavaScript文件

          此種嵌入方法可以指定defer、async屬性。defer可以推遲執行,async可以異步執行。

          3 onload嵌入

          此種嵌入方法在頁面讀取完后再對其執行,所以可以對所有的DOM元素操作。

          <body onload="alert('hello')">
          window.onload=function(){alert('hello');};

          當window.onload事件觸發時,頁面上所有的DOM、樣式表、腳本、圖片、flash都已經加載完成了。

          //window.onload不能同時編寫多個。
          //以下代碼無法正確執行,結果只輸出第二個。
          window.onload=function(){
            alert("test1");
          };
          
          window.onload=function(){
            alert("test2");
          };
          
          //$(document).ready()能同時編寫多個
          //結果兩次都輸出
          $(document).ready(function(){ 
             alert("Hello World"); 
          }); 
          $(document).ready(function(){ 
             alert("Hello again"); 
          }); 

          window.onload和body中onload也有些許區別:

          <html xmlns="http://www.w3.org/1999/xhtml">
          <head>
              <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
              <title></title>
              <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.0.js"></script>
              <script language="javascript">
                  window.onload=haha;
                  function haha(){console.log("window.onload");}
          
                  if(document.addEventListener){
                      function DOMContentLoaded(){
                          console.log("DOMContentLoaded");
                      }
                      document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
                  }</script>
          </head>
          <body onload="console.log('bodyonload');">
                  <div id="div1">a</div>
          </body>
          </html>

          在IE10和FireFox下,結果為 :

          "DOMContentLoaded"
          "bodyonload"

          說明body中的onload會覆蓋window.onload

          在chrome下,結果為:

          DOMContentLoaded
          window.onload
          bodyonload

          然后,如果把javascript代碼移到最下面,結果又會是什么樣呢?

          chrome和IE10、FireFox的結果竟然是一樣的:

          DOMContentLoaded
          window.onload

          IE 10、Fire Fox可以理解,window.on load和body中的 on load 誰在下面就是誰覆蓋誰,只會執行后面的那個。

          4 DOM ContentLoaded嵌入

          onload方法可能需要等待時間,而本方法可以在完成HTML解析后發生的事件,減少等待時間。

          在chrome、IE10和FireFox中,執行結果是:DOMContentLoaded然后才是onload的輸出。所以說一般情況下,DOMContentLoaded事件要在window.onload之前執行,當DOM樹構建完成的時候就會執行DOMContentLoaded事件。

          <html xmlns="http://www.w3.org/1999/xhtml">
          <head>
              <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
              <title></title>
              <script type="text/javascript" src="jquery2.js"></script>
              <script language="javascript">
                  window.onload=haha;
                  function haha(){console.log(document.getElementById("div1"));}
                  if(document.addEventListener){
                      function DOMContentLoaded(){
                          console.log("DOMContentLoaded");
                      }
                      document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
                  }
              </script>
          </head>
          <body>
              <div id="div1">a</div>
          </body>
          </html>

          如果你是個jQuery使用者,你可能會經常使用$(document).ready();或者$(function(){}),這都是使用了DOMContentLoaded事件

          5 動態載入JavaScript文件

          5.1 使用原生js方法

          動態創建script標簽,并指定script的src屬性

          function loadJs(url, callback) {
              var script=document.createElement('script');
              script.type="text/javascript";
              if (typeof(callback) !="undefined") {
                  if (script.readyState) {
                      script.onreadystatechange=function() {
                          if (script.readyState=="loaded" || script.readyState=="complete") {
                              script.onreadystatechange=null;
                              callback();
                          }
                      }
                  } else {
                      script.onload=function() {
                          callback();
                      }
                  }
              }
              script.src=url;
              document.body.appendChild(script);
          }
          loadJs("test.js", function() {
              alert('done');
          });

          還可以使用同樣的原理動態加載css文件,只不過插入的的父節點是head標簽。

          5.2 使用document.write/writeln()方式

          該種方式可以實現js文件的動態加載,原理就是在重寫文檔流,這種方式會導致整個頁面重繪。

          document.writeln("<script src=\"http://lib.sinaapp.com/js/jquery/1.6/jquery.min.js\"></script>");

          需要注意的是特殊字符的轉義。

          5.3 使用jQuery

          使用getScript(url,callback)方法實現動態加載js文件

          $.getScript('test.js',function(){
              alert('done');
          });

          -End-


          主站蜘蛛池模板: 国产a∨精品一区二区三区不卡 | 亚洲av日韩综合一区久热| 国产剧情国产精品一区| 人妻久久久一区二区三区 | 精品国产一区二区三区久久久狼| 亚洲一区二区三区乱码在线欧洲| 在线电影一区二区三区| 国产激情一区二区三区 | 久久久久人妻精品一区蜜桃| 亚洲欧美国产国产综合一区 | 亚洲国产精品第一区二区| 在线成人一区二区| 久久精品国产第一区二区| 亚洲av不卡一区二区三区| 国精产品一区一区三区MBA下载| 亚洲国产精品一区二区九九| 久热国产精品视频一区二区三区| 怡红院美国分院一区二区| 国产午夜精品一区二区三区不卡| 免费无码VA一区二区三区| 高清无码一区二区在线观看吞精| 久久亚洲一区二区| 国产精品无码一区二区三区在 | 久久99国产精一区二区三区| 成人丝袜激情一区二区| 一区二区三区国产| 八戒久久精品一区二区三区| 亚洲国产一区国产亚洲| 精品91一区二区三区| 一区二区三区日韩| 日韩精品无码久久一区二区三| 亚洲一区二区电影| 国产AV国片精品一区二区| 亚洲综合在线一区二区三区| 中文无码精品一区二区三区| 精品无码人妻一区二区三区18| 农村人乱弄一区二区 | 久久精品视频一区| 精品免费久久久久国产一区 | 四虎成人精品一区二区免费网站 | 无码av中文一区二区三区桃花岛 |