目錄
javascript作用域
物件的讀取
DOM操作最佳化
首頁 web前端 js教程 javascript效能優化的方法介紹(附範例)

javascript效能優化的方法介紹(附範例)

Nov 17, 2018 pm 03:03 PM
html html5 javascript 前端 效能最佳化

這篇文章帶給大家的內容是關於javascript效能優化的方法介紹(附範例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。

本文主要是在我讀《高效能Javascript》之後,想要記錄下一些有用的優化方案,並且就我本身的一些經驗,來大家一起分享下,

#Javascript的載入與執行

大家都知道,瀏覽器在解析DOM樹的時候,當解析到script標籤的時候,會阻塞其他的所有任務,直到該js檔案下載、解析執行完成後,才會繼續往下執行。因此,這個時候瀏覽器就會被阻塞在這裡,如果將script標籤放在head裡的話,那麼在該js檔案載入執行前,使用者只能看到空白的頁面,這樣的使用者體驗肯定是特別爛。對此,常用的方法有以下:

  • 將所有的script標籤都放到body最底部,這樣可以保證js檔案是最後載入並執行的,可以先將頁面展現給用戶。但是,你首先得清楚,頁面的首屏渲染是否依賴於你的部分js文件,如果是的話,則需要將這一部分js文件放到head上。

  • 使用defer,例如下面這種寫法。使用defer這種寫法時,雖然瀏覽器解析到該標籤的時候,也會下載對應的js文件,不過它並不會馬上執行,而是會等到DOM解析完後(DomContentLoader之前)才會執行這些js文件。因此,就不會阻塞到瀏覽器。

<script src="test.js" type="text/javascript" defer></script>
登入後複製
  • 動態載入js檔案,透過這種方式,可以在頁面載入完成後,再去載入所需要的程式碼,也可以透過這種方式實作js檔案懶加載/按需加載,例如現在比較常見的,就是webpack結合vue-router/react-router實現按需加載,只有訪問到具體路由的時候,才加載相應的程式碼。具體的方法如下:

1.動態的插入script標籤來載入腳本,例如透過以下程式碼

  function loadScript(url, callback) {
    const script = document.createElement('script');
    script.type = 'text/javascript';
    // 处理IE
    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.append(script);
  }

  // 动态加载js
  loadScript('file.js', function () {
    console.log('加载完成');
  })
登入後複製

2.透過xhr方式載入js文件,不過透過這種方式的話,就可能面臨跨域的問題。範例如下:

  const xhr = new XMLHttpRequest();
  xhr.open('get', 'file.js');
  xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
      if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
        const script = document.createElement('script');
        script.type = 'text/javascript';
        script.text = xhr.responseText;
        document.body.append(script);
      }
    }
  }
登入後複製

3.將多個js檔案合併為同一個,並且進行壓縮。原因:目前瀏覽器大多已經支援並行下載js檔案了,但是並發下載還是有一定的數量限制了(基於瀏覽器,一部分瀏覽器只能下載4個),並且,每一個js檔案都需要建立一次額外的http連接,載入4個25KB的檔案比起載入一個100KB的檔案消耗的時間要大。因此,我們最好就是將多個js檔案合併為同一個,並且進行程式碼壓縮。

javascript作用域

當一個函數執行的時候,會產生一個執行上下文,這個執行上下文定義了函數執行時的環境。當函數執行完畢後,這個執行上下文就會被銷毀。因此,多次呼叫同一個函數會導致建立多個執行上下文。每隔執行上下文都有自己的作用域鏈。相信大家應該早就知道了作用域這個東西,對於一個函數而言,其第一個作用域就是它函數內部的變數。在函數執行過程中,每遇到一個變量,都會搜尋函數的作用域鏈找到第一個匹配的變量,首先查找函數內部的變量,之後再沿著作用域鏈逐層尋找。因此,若我們要存取最外層的變數(全域變數),則比起直接存取內部的變數而言,會帶來比較大的效能損耗。因此,我們可以將經常使用的全域變數參考儲存在一個局部變數裡

const a = 5;
function outter () {
  const a = 2;
  function inner () {
    const b = 2;
    console.log(b); // 2
    console.log(a); // 2
  }
  inner();
}
登入後複製

物件的讀取

javascript中,主要分為字面量、局部變數、陣列元素和物件這四種。存取字面量和局部變數的速度最快,而存取陣列元素和物件成員相對較慢。而訪問物件成員的時候,就和作用域鏈一樣,就是在原型鏈(prototype)上進行查找。因此,若查找的成員在原型鏈位置太深,則存取速度越慢。因此,我們應該盡可能的減少物件成員的查找次數和巢狀深度。例如以下程式碼

  // 进行两次对象成员查找
  function hasEitherClass(element, className1, className2) {
    return element.className === className1 || element.className === className2;
  }
  // 优化,如果该变量不会改变,则可以使用局部变量保存查找的内容
  function hasEitherClass(element, className1, className2) {
    const currentClassName = element.className;
    return currentClassName === className1 || currentClassName === className2;
  }
登入後複製

DOM操作最佳化

  • 最小化DOM的操作次數,盡可能的用javascript來處理,並且盡可能的使用局部變數儲存DOM節點。例如以下的程式碼:

  // 优化前,在每次循环的时候,都要获取id为t的节点,并且设置它的innerHTML
  function innerHTMLLoop () {
    for (let count = 0; count < 15000; count++) {
      document.getElementById('t').innerHTML += 'a';
    }
  }
  // 优化后,
  function innerHTMLLoop () {
    const tNode = document.getElemenById('t');
    const insertHtml = '';
    for (let count = 0; count < 15000; count++) {
      insertHtml += 'a';
    }
    tNode.innerHtml += insertHtml;
  }
登入後複製
  • 盡可能的減少重排和重繪,重排和重匯可能會代價非常昂貴,因此,為了減少重排重彙的發生次數,我們可以做以下的優化

1.當我們要對Dom的樣式進行修改的時候,我們應該盡可能的合併所有的修改並且一次處理,減少重排和重彙的次數。

  // 优化前
  const el = document.getElementById('test');
  el.style.borderLeft = '1px';
  el.style.borderRight = '2px';
  el.style.padding = '5px';

  // 优化后,一次性修改样式,这样可以将三次重排减少到一次重排
  const el = document.getElementById('test');
  el.style.cssText += '; border-left: 1px ;border-right: 2px; padding: 5px;'
登入後複製

2.当我们要批量修改DOM节点的时候,我们可以将DOM节点隐藏掉,然后进行一系列的修改操作,之后再将其设置为可见,这样就可以最多只进行两次重排。具体的方法如下:

  // 未优化前
  const ele = document.getElementById('test');
  // 一系列dom修改操作

  // 优化方案一,将要修改的节点设置为不显示,之后对它进行修改,修改完成后再显示该节点,从而只需要两次重排
  const ele = document.getElementById('test');
  ele.style.display = 'none';
  // 一系列dom修改操作
  ele.style.display = 'block';

  // 优化方案二,首先创建一个文档片段(documentFragment),然后对该片段进行修改,之后将文档片段插入到文档中,只有最后将文档片段插入文档的时候会引起重排,因此只会触发一次重排。。
  const fragment = document.createDocumentFragment();
  const ele = document.getElementById('test');
  // 一系列dom修改操作
  ele.appendChild(fragment);
登入後複製

3.使用事件委托:事件委托就是将目标节点的事件移到父节点来处理,由于浏览器冒泡的特点,当目标节点触发了该事件的时候,父节点也会触发该事件。因此,由父节点来负责监听和处理该事件。

那么,它的优点在哪里呢?假设你有一个列表,里面每一个列表项都需要绑定相同的事件,而这个列表可能会频繁的插入和删除。如果按照平常的方法,你只能给每一个列表项都绑定一个事件处理器,并且,每当插入新的列表项的时候,你也需要为新的列表项注册新的事件处理器。这样的话,如果列表项很大的话,就会导致有特别多的事件处理器,造成极大的性能问题。而通过事件委托,我们只需要在列表项的父节点监听这个事件,由它来统一处理就可以了。这样,对于新增的列表项也不需要做额外的处理。而且事件委托的用法其实也很简单:

function handleClick(target) {
  // 点击列表项的处理事件
}
function delegate (e) {
  // 判断目标对象是否为列表项
  if (e.target.nodeName === 'LI') {
    handleClick(e.target);
  }
}
const parent = document.getElementById('parent');
parent.addEventListener('click', delegate);
登入後複製


以上是javascript效能優化的方法介紹(附範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

HTML 中的表格邊框 HTML 中的表格邊框 Sep 04, 2024 pm 04:49 PM

HTML 表格邊框指南。在這裡,我們以 HTML 中的表格邊框為例,討論定義表格邊框的多種方法。

HTML 中的巢狀表 HTML 中的巢狀表 Sep 04, 2024 pm 04:49 PM

這是 HTML 中巢狀表的指南。這裡我們討論如何在表中建立表格以及對應的範例。

HTML 左邊距 HTML 左邊距 Sep 04, 2024 pm 04:48 PM

HTML 左邊距指南。在這裡,我們討論 HTML margin-left 的簡要概述及其範例及其程式碼實作。

HTML 表格佈局 HTML 表格佈局 Sep 04, 2024 pm 04:54 PM

HTML 表格佈局指南。在這裡,我們詳細討論 HTML 表格佈局的值以及範例和輸出。

HTML 輸入佔位符 HTML 輸入佔位符 Sep 04, 2024 pm 04:54 PM

HTML 輸入佔位符指南。在這裡,我們討論 HTML 輸入佔位符的範例以及程式碼和輸出。

HTML 有序列表 HTML 有序列表 Sep 04, 2024 pm 04:43 PM

HTML 有序列表指南。在這裡我們也分別討論了 HTML 有序列表和類型的介紹以及它們的範例

HTML onclick 按鈕 HTML onclick 按鈕 Sep 04, 2024 pm 04:49 PM

HTML onclick 按鈕指南。這裡我們分別討論它們的介紹、工作原理、範例以及各個事件中的onclick事件。

在 HTML 中移動文字 在 HTML 中移動文字 Sep 04, 2024 pm 04:45 PM

HTML 中的文字移動指南。在這裡我們討論一下marquee標籤如何使用語法和實作範例。

See all articles