ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript のパフォーマンス最適化方法の概要 (例付き)

JavaScript のパフォーマンス最適化方法の概要 (例付き)

不言
不言転載
2018-11-17 15:03:412458ブラウズ

この記事では、JavaScript のパフォーマンスを最適化する方法を紹介します (例を示します)。必要な方は参考にしてください。

この記事は主に「ハイパフォーマンス JavaScript」を読んだ後に書かれたものです。いくつかの有用な最適化ソリューションを記録し、私自身の経験の一部を皆さんと共有したいと思います。

読み込みと実行ご存知のとおり、ブラウザは DOM ツリーを解析するとき、スクリプト タグを解析するとき、解析の実行が完了した後、js ファイルがダウンロードされるまで他のすべてのタスクをブロックします。 、実行は続行されます。したがって、この時点でブラウザはブロックされ、head に script タグが配置されている場合、ユーザーは js ファイルがロードされて実行される前に空白のページしか表示されなくなります。このユーザー エクスペリエンスは特に悪くなるはずです。この点に関して、一般的に使用される方法は次のとおりです。

すべてのスクリプト タグを本文の最後に配置すると、js ファイルが最後にロードされて実行されるようになります。ページを最初にユーザーに表示できます。ただし、最初にページの最初の画面のレンダリングが js ファイルの一部に依存しているかどうかを知る必要があります。依存している場合は、js ファイルのこの部分を先頭に置く必要があります。
  • 次のような書き方で defer を使います。 defer を使用すると、ブラウザーはタグを解析するときに対応する js ファイルをダウンロードしますが、すぐには実行されず、DOM が解析されるまで (DomContentLoader の前に) 待機してからこれらの js ドキュメントを実行します。したがって、ブラウザはブロックされません。
  • <script src="test.js" type="text/javascript" defer></script>
この方法では、ページが読み込まれた後に必要なコードを読み込むことができます。この方法を使用することもできます。たとえば、webpack を vue-router/react-router と組み合わせて、特定のルートにアクセスしたときにのみ対応するコードが読み込まれることが一般的になっています。具体的な方法は次のとおりです。
  • 1. 次のコード
  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 を使用して、スクリプト タグを動的に挿入します。しかし、この方法では、クロスドメインの問題に直面する可能性があります。例は次のとおりです:

  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 ファイルを 1 つに結合し、圧縮します。理由: 現在、ほとんどのブラウザーは js ファイルの並列ダウンロードをサポートしていますが、同時ダウンロード数には依然として一定の制限があり (ブラウザーによっては、一部のブラウザーは 4 つしかダウンロードできません)、各 js ファイルは追加のファイルを作成する必要があります。 http 接続では、25 KB ファイルを 4 つロードすると、100 KB ファイルを 1 つロードするよりも時間がかかります。したがって、最善の選択肢は、複数の js ファイルを 1 つにマージし、コードを圧縮することです。

javascript スコープ

関数が実行されると、実行コンテキストが生成され、関数が実行されるときの環境が定義されます。関数の実行が完了すると、実行コンテキストは破棄されます。したがって、同じ関数を複数回呼び出すと、複数の実行コンテキストが作成されます。各実行コンテキストには独自のスコープ チェーンがあります。関数のスコープについては、誰もが長い間知っていたはずです。関数の最初のスコープは関数内の変数です。関数の実行中、変数が見つかるたびに、最初に一致する変数を見つけるために関数のスコープ チェーンが検索され、次にスコープ チェーンに沿ってレイヤーごとに検索されます。したがって、

最も外側の変数 (グローバル変数) にアクセスする場合、内部変数に直接アクセスする場合と比較して、比較的大きなパフォーマンスの損失が発生します。したがって、

頻繁に使用されるグローバル変数参照をローカル変数に保存できます

const a = 5;
function outter () {
  const a = 2;
  function inner () {
    const b = 2;
    console.log(b); // 2
    console.log(a); // 2
  }
  inner();
}
オブジェクトの読み取りJavaScript には、リテラル、ローカル変数、配列要素、オブジェクトの 4 つの主なタイプがあります。リテラルとローカル変数へのアクセスは最も高速ですが、配列要素とオブジェクト メンバーへのアクセスは比較的遅くなります。オブジェクト メンバーにアクセスするときは、スコープ チェーンと同様に、プロトタイプ チェーンで検索が実行されます。したがって、検索されたメンバーがプロトタイプ チェーンの深すぎる場合、アクセス速度が遅くなります。したがって、

オブジェクト メンバーのルックアップの数とネストの深さを可能な限り減らす必要があります。たとえば、次のコード

  // 进行两次对象成员查找
  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操作を実行します。可能な限り 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 中国語 Web サイトの他の関連記事を参照してください。

    声明:
    この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。