目次
总结
ホームページ ウェブフロントエンド jsチュートリアル JS でのメモリ リークを防ぐにはどうすればよいですか?よくある 5 つの記憶エラーについて話しましょう

JS でのメモリ リークを防ぐにはどうすればよいですか?よくある 5 つの記憶エラーについて話しましょう

Dec 31, 2021 am 10:57 AM
javascript メモリエラー

JS でのメモリ リークを防ぐにはどうすればよいですか?よくある 5 つの記憶エラーについて話しましょう

#JavaScript はメモリ管理操作を提供しません。代わりに、メモリは、ガベージ コレクションと呼ばれるメモリ再利用プロセスを通じて JavaScript VM によって管理されます。

ガベージ コレクションを強制することはできないので、ガベージ コレクションが適切に機能することをどのように確認すればよいでしょうか?私たちはそれについてどれくらい知っていますか?

このプロセス中はスクリプトの実行が一時停止されます

    アクセスできないリソースのメモリが解放されます
  • 未定義です
  • メモリ全体をチェックするわけではありません
  • これは予測不可能ですが、必要に応じて実行されます
  • これは、リソースとメモリの分散の問題を心配する必要がないことを意味しますか? もちろんそうではありません。注意しないと、メモリ リークが発生する可能性があります。

#メモリ リークとは何ですか?

JS でのメモリ リークを防ぐにはどうすればよいですか?よくある 5 つの記憶エラーについて話しましょう#メモリ リークとは、ソフトウェアによって再利用できない、割り当てられたメモリのブロックです。

Javascript はガベージ コレクターを提供しますが、これはメモリ リークを回避できることを意味するものではありません。ガベージ コレクションの対象となるには、オブジェクトが他の場所で参照されていてはなりません。未使用のリソースへの参照を保持すると、それらのリソースが再利用されなくなります。これは、

無意識の記憶保持と呼ばれます。

メモリのリークにより、ガベージ コレクターがより頻繁に実行される可能性があります。このプロセスによりスクリプトの実行が妨げられるため、プログラムがフリーズする可能性があります。このような遅延が発生すると、うるさいユーザーは、満足できない場合は製品が長時間オフラインになることに間違いなく気づくでしょう。さらに深刻なことに、アプリケーション全体がクラッシュする可能性があります。これは gg です。

メモリ リークを防ぐにはどうすればよいでしょうか? 重要なのは、不必要なリソースを保持しないようにすることです。いくつかの一般的なシナリオを見てみましょう。

1. タイマー監視

setInterval() メソッドは、毎回関数を繰り返し呼び出すか、コード フラグメントを実行します。呼び出しの間には固定の時間遅延があります。間隔を一意に識別する間隔 ID

が返されるため、後で

clearInterval() を呼び出して削除できます。 # ループの後に完了したことを示すコールバック関数を呼び出すコンポーネントを作成します。この例では React を使用していますが、これはどの FE フレームワークでも機能します。

import React, { useRef } from 'react';

const Timer = ({ cicles, onFinish }) => {
    const currentCicles = useRef(0);

    setInterval(() => {
        if (currentCicles.current >= cicles) {
            onFinish();
            return;
        }
        currentCicles.current++;
    }, 500);

    return (
        <div>Loading ...</div>
    );
}

export default Timer;
ログイン後にコピー
一見すると問題ないようです。心配しないで、このタイマーをトリガーする別のコンポーネントを作成し、そのメモリ パフォーマンスを分析しましょう。
import React, { useState } from &#39;react&#39;;
import styles from &#39;../styles/Home.module.css&#39;
import Timer from &#39;../components/Timer&#39;;

export default function Home() {
    const [showTimer, setShowTimer] = useState();
    const onFinish = () => setShowTimer(false);

    return (
      <div className={styles.container}>
          {showTimer ? (
              <Timer cicles={10} onFinish={onFinish} />
          ): (
              <button onClick={() => setShowTimer(true)}>
                Retry
              </button>
          )}
      </div>
    )
}
ログイン後にコピー

Retry ボタンを数回クリックした後、Chrome デベロッパー ツールを使用してメモリ使用量を取得した結果が次のとおりです:

再試行ボタンをクリックすると、より多くのメモリが割り当てられることがわかります。これは、以前に割り当てられたメモリが解放されていないことを意味します。タイマーは交換されずにまだ動作しています。 この問題を解決するにはどうすればよいですか?

setInterval

の戻り値は間隔 ID であり、この間隔をキャンセルするために使用できます。この特定のケースでは、コンポーネントがアンロードされた後に JS でのメモリ リークを防ぐにはどうすればよいですか?よくある 5 つの記憶エラーについて話しましょうclearInterval

を呼び出すことができます。

useEffect(() => {
    const intervalId = setInterval(() => {
        if (currentCicles.current >= cicles) {
            onFinish();
            return;
        }
        currentCicles.current++;
    }, 500);

    return () => clearInterval(intervalId);
}, [])
ログイン後にコピー

コードを作成するときにこの問題を見つけるのが難しい場合がありますが、最善の方法はコンポーネントを抽象化することです。

ここでは React が使用されており、このロジックすべてをカスタム フックにラップできます。

import { useEffect } from &#39;react&#39;;

export const useTimeout = (refreshCycle = 100, callback) => {
    useEffect(() => {
        if (refreshCycle <= 0) {
            setTimeout(callback, 0);
            return;
        }

        const intervalId = setInterval(() => {
            callback();
        }, refreshCycle);

        return () => clearInterval(intervalId);
    }, [refreshCycle, setInterval, clearInterval]);
};

export default useTimeout;
ログイン後にコピー
setInterval

を使用する必要がある場合は、次のようにすることができます:

const handleTimeout = () => ...;

useTimeout(100, handleTimeout);
ログイン後にコピー

これで、心配することなく、この

useTimeout フック

を使用できるようになります。メモリのリークについてですが、これも抽象化の利点です。

2. イベント リスニング

Web API は多数のイベント リスナーを提供します。前に、

setTimeout について説明しました。次に、addEventListener を見てみましょう。

この例では、キーボード ショートカット関数を作成します。さまざまなページにさまざまな機能があるため、さまざまなショートカット キー機能が作成されます。

function homeShortcuts({ key}) {
    if (key === &#39;E&#39;) {
        console.log(&#39;edit widget&#39;)
    }
}

// 用户在主页上登陆,我们执行
document.addEventListener(&#39;keyup&#39;, homeShortcuts); 


// 用户做一些事情,然后导航到设置

function settingsShortcuts({ key}) {
    if (key === &#39;E&#39;) {
        console.log(&#39;edit setting&#39;)
    }
}

// 用户在主页上登陆,我们执行
document.addEventListener(&#39;keyup&#39;, settingsShortcuts);
ログイン後にコピー
は、2 番目の addEventListener を実行する前にクリーンアップがないことを除けば、引き続き問題ないようです。 keyup## #。このコードは、

keyup

リスナーを置き換えるのではなく、別の

callback

を追加します。これは、キーが押されると 2 つの機能がトリガーされることを意味します。 前のコールバックをクリアするには、removeEventListener :<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">document.removeEventListener(‘keyup’, homeShortcuts);</pre><div class="contentsignin">ログイン後にコピー</div></div>上記のコードをリファクタリングする必要があります: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">function homeShortcuts({ key}) { if (key === &amp;#39;E&amp;#39;) { console.log(&amp;#39;edit widget&amp;#39;) } } // user lands on home and we execute document.addEventListener(&amp;#39;keyup&amp;#39;, homeShortcuts); // user does some stuff and navigates to settings function settingsShortcuts({ key}) { if (key === &amp;#39;E&amp;#39;) { console.log(&amp;#39;edit setting&amp;#39;) } } // user lands on home and we execute document.removeEventListener(&amp;#39;keyup&amp;#39;, homeShortcuts); document.addEventListener(&amp;#39;keyup&amp;#39;, settingsShortcuts);</pre><div class="contentsignin">ログイン後にコピー</div></div>経験によれば、from を使用する場合は、グローバル オブジェクト ツールを使用する場合は、細心の注意を払ってください。

3.Observers

Observers

は、多くの開発者が知らないブラウザの Web API 関数です。これは、HTML 要素の可視性やサイズの変更を確認する場合に強力です。

IntersectionObserver接口 (从属于Intersection Observer API) 提供了一种异步观察目标元素与其祖先元素或顶级文档视窗(viewport)交叉状态的方法。祖先元素与视窗(viewport)被称为根(root)。

尽管它很强大,但我们也要谨慎的使用它。一旦完成了对对象的观察,就要记得在不用的时候取消它。

看看代码:

const ref = ...
const visible = (visible) => {
  console.log(`It is ${visible}`);
}

useEffect(() => {
    if (!ref) {
        return;
    }

    observer.current = new IntersectionObserver(
        (entries) => {
            if (!entries[0].isIntersecting) {
                visible(true);
            } else {
                visbile(false);
            }
        },
        { rootMargin: `-${header.height}px` },
    );

    observer.current.observe(ref);
}, [ref]);
ログイン後にコピー

上面的代码看起来不错。然而,一旦组件被卸载,观察者会发生什么?它不会被清除,那内存可就泄漏了。我们怎么解决这个问题呢?只需要使用 disconnect 方法:

const ref = ...
const visible = (visible) => {
  console.log(`It is ${visible}`);
}

useEffect(() => {
    if (!ref) {
        return;
    }

    observer.current = new IntersectionObserver(
        (entries) => {
            if (!entries[0].isIntersecting) {
                visible(true);
            } else {
                visbile(false);
            }
        },
        { rootMargin: `-${header.height}px` },
    );

    observer.current.observe(ref);

    return () => observer.current?.disconnect();
}, [ref]);
ログイン後にコピー

4. Window Object

向 Window 添加对象是一个常见的错误。在某些场景中,可能很难找到它,特别是在使用 Window Execution上下文中的this关键字。看看下面的例子:

function addElement(element) {
    if (!this.stack) {
        this.stack = {
            elements: []
        }
    }

    this.stack.elements.push(element);
}
ログイン後にコピー

它看起来无害,但这取决于你从哪个上下文调用addElement。如果你从Window Context调用addElement,那就会越堆越多。

另一个问题可能是错误地定义了一个全局变量:

var a = &#39;example 1&#39;; // 作用域限定在创建var的地方
b = &#39;example 2&#39;; // 添加到Window对象中
ログイン後にコピー

要防止这种问题可以使用严格模式:

"use strict"
ログイン後にコピー

通过使用严格模式,向JavaScript编译器暗示,你想保护自己免受这些行为的影响。当你需要时,你仍然可以使用Window。不过,你必须以明确的方式使用它。

严格模式是如何影响我们前面的例子:

  • 对于 addElement 函数,当从全局作用域调用时,this 是未定义的
  • 如果没有在一个变量上指定const | let | var,你会得到以下错误:
Uncaught ReferenceError: b is not defined
ログイン後にコピー

5. 持有DOM引用

DOM节点也不能避免内存泄漏。我们需要注意不要保存它们的引用。否则,垃圾回收器将无法清理它们,因为它们仍然是可访问的。

用一小段代码演示一下:

const elements = [];
const list = document.getElementById(&#39;list&#39;);

function addElement() {
    // clean nodes
    list.innerHTML = &#39;&#39;;

    const divElement= document.createElement(&#39;div&#39;);
    const element = document.createTextNode(`adding element ${elements.length}`);
    divElement.appendChild(element);


    list.appendChild(divElement);
    elements.push(divElement);
}

document.getElementById(&#39;addElement&#39;).onclick = addElement;
ログイン後にコピー

注意,addElement 函数清除列表 div,并将一个新元素作为子元素添加到它中。这个新创建的元素被添加到 elements 数组中。

下一次执行 addElement 时,该元素将从列表 div 中删除,但是它不适合进行垃圾收集,因为它存储在 elements 数组中。

我们在执行几次之后监视函数:

JS でのメモリ リークを防ぐにはどうすればよいですか?よくある 5 つの記憶エラーについて話しましょう

在上面的截图中看到节点是如何被泄露的。那怎么解决这个问题?清除 elements  数组将使它们有资格进行垃圾收集。

总结

在这篇文章中,我们已经看到了最常见的内存泄露方式。很明显,JavaScript本身并没有泄漏内存。相反,它是由开发者方面无意的内存保持造成的。只要代码是整洁的,而且我们不忘自己清理,就不会发生泄漏。

了解内存和垃圾回收在JavaScript中是如何工作的是必须的。一些开发者得到了错误的意识,认为由于它是自动的,所以他们不需要担心这个问题。

原文地址:https://betterprogramming.pub/5-common-javascript-memory-mistakes-c8553972e4c2

作者: Jose Granja

译者:前端小智

【相关推荐:javascript学习教程

以上がJS でのメモリ リークを防ぐにはどうすればよいですか?よくある 5 つの記憶エラーについて話しましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 Dec 17, 2023 pm 02:54 PM

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 はじめに: 技術の継続的な発展により、音声認識技術は人工知能の分野の重要な部分になりました。 WebSocket と JavaScript をベースとしたオンライン音声認識システムは、低遅延、リアルタイム、クロスプラットフォームという特徴があり、広く使用されるソリューションとなっています。この記事では、WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法を紹介します。

メモリが読み取れない場合はどうすればよいですか? メモリが読み取れない場合はどうすればよいですか? Jan 07, 2024 pm 04:53 PM

友達がたくさんパソコンを使っていると、突然「メモリが読み取れずクラッシュする」というダイアログが表示されて困惑していると思いますが、何が起こっているのでしょうか?実際、これはドライバーが不安定であるか更新されていないため、オペレーティング システムがコンピューター ハードウェアと互換性がなく、メモリを読み取れないエラーが発生しやすいためです。このエラーはソフトウェア ツールを使用してワンクリックで修復できます。メモリが読み取れない場合の対処方法: タイプ 1: 修復ツール 1. 特別な修復ツールをダウンロードします。 2. ダウンロード後、解凍して「ワンクリック修復メモリが読み取れません」を実行すると問題が解決します。 2 番目のタイプ: 手動修復 1. まず、ショートカット キー Windows + R を押し、ファイル名を指定して実行を開き、「CMD」と入力して Enter を押します。 2. コマンドプロンプトを開いた後、次のように入力します。

WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー Dec 17, 2023 pm 05:30 PM

WebSocketとJavaScript:リアルタイム監視システムを実現するためのキーテクノロジー はじめに: インターネット技術の急速な発展に伴い、リアルタイム監視システムは様々な分野で広く利用されています。リアルタイム監視を実現するための重要なテクノロジーの 1 つは、WebSocket と JavaScript の組み合わせです。この記事では、リアルタイム監視システムにおける WebSocket と JavaScript のアプリケーションを紹介し、コード例を示し、その実装原理を詳しく説明します。 1.WebSocketテクノロジー

JavaScript と WebSocket を使用してリアルタイムのオンライン注文システムを実装する方法 JavaScript と WebSocket を使用してリアルタイムのオンライン注文システムを実装する方法 Dec 17, 2023 pm 12:09 PM

JavaScript と WebSocket を使用してリアルタイム オンライン注文システムを実装する方法の紹介: インターネットの普及とテクノロジーの進歩に伴い、ますます多くのレストランがオンライン注文サービスを提供し始めています。リアルタイムのオンライン注文システムを実装するには、JavaScript と WebSocket テクノロジを使用できます。 WebSocket は、TCP プロトコルをベースとした全二重通信プロトコルで、クライアントとサーバー間のリアルタイム双方向通信を実現します。リアルタイムオンラインオーダーシステムにおいて、ユーザーが料理を選択して注文するとき

WebSocketとJavaScriptを使ったオンライン予約システムの実装方法 WebSocketとJavaScriptを使ったオンライン予約システムの実装方法 Dec 17, 2023 am 09:39 AM

WebSocket と JavaScript を使用してオンライン予約システムを実装する方法 今日のデジタル時代では、ますます多くの企業やサービスがオンライン予約機能を提供する必要があります。効率的かつリアルタイムのオンライン予約システムを実装することが重要です。この記事では、WebSocket と JavaScript を使用してオンライン予約システムを実装する方法と、具体的なコード例を紹介します。 1. WebSocket とは何ですか? WebSocket は、単一の TCP 接続における全二重方式です。

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 Dec 17, 2023 pm 05:13 PM

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 はじめに: 今日、天気予報の精度は日常生活と意思決定にとって非常に重要です。テクノロジーの発展に伴い、リアルタイムで気象データを取得することで、より正確で信頼性の高い天気予報を提供できるようになりました。この記事では、JavaScript と WebSocket テクノロジを使用して効率的なリアルタイム天気予報システムを構築する方法を学びます。この記事では、具体的なコード例を通じて実装プロセスを説明します。私たちは

簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 Jan 05, 2024 pm 06:08 PM

JavaScript チュートリアル: HTTP ステータス コードを取得する方法、特定のコード例が必要です 序文: Web 開発では、サーバーとのデータ対話が頻繁に発生します。サーバーと通信するとき、多くの場合、返された HTTP ステータス コードを取得して操作が成功したかどうかを判断し、さまざまなステータス コードに基づいて対応する処理を実行する必要があります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法を説明し、いくつかの実用的なコード例を示します。 XMLHttpRequestの使用

JavaScriptでinsertBeforeを使用する方法 JavaScriptでinsertBeforeを使用する方法 Nov 24, 2023 am 11:56 AM

使用法: JavaScript では、insertBefore() メソッドを使用して、DOM ツリーに新しいノードを挿入します。このメソッドには、挿入される新しいノードと参照ノード (つまり、新しいノードが挿入されるノード) の 2 つのパラメータが必要です。

See all articles