JS でのメモリ リークを防ぐにはどうすればよいですか?よくある 5 つの記憶エラーについて話しましょう
ガベージ コレクションを強制することはできないので、ガベージ コレクションが適切に機能することをどのように確認すればよいでしょうか?私たちはそれについてどれくらい知っていますか?
このプロセス中はスクリプトの実行が一時停止されます
- アクセスできないリソースのメモリが解放されます
- 未定義です
- メモリ全体をチェックするわけではありません
- これは予測不可能ですが、必要に応じて実行されます
- これは、リソースとメモリの分散の問題を心配する必要がないことを意味しますか? もちろんそうではありません。注意しないと、メモリ リークが発生する可能性があります。
#メモリ リークとは、ソフトウェアによって再利用できない、割り当てられたメモリのブロックです。
無意識の記憶保持と呼ばれます。
メモリのリークにより、ガベージ コレクターがより頻繁に実行される可能性があります。このプロセスによりスクリプトの実行が妨げられるため、プログラムがフリーズする可能性があります。このような遅延が発生すると、うるさいユーザーは、満足できない場合は製品が長時間オフラインになることに間違いなく気づくでしょう。さらに深刻なことに、アプリケーション全体がクラッシュする可能性があります。これは 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 'react'; import styles from '../styles/Home.module.css' import Timer from '../components/Timer'; 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 デベロッパー ツールを使用してメモリ使用量を取得した結果が次のとおりです:
再試行ボタンをクリックすると、より多くのメモリが割り当てられることがわかります。これは、以前に割り当てられたメモリが解放されていないことを意味します。タイマーは交換されずにまだ動作しています。 この問題を解決するにはどうすればよいですか?
の戻り値は間隔 ID であり、この間隔をキャンセルするために使用できます。この特定のケースでは、コンポーネントがアンロードされた後に clearInterval
useEffect(() => { const intervalId = setInterval(() => { if (currentCicles.current >= cicles) { onFinish(); return; } currentCicles.current++; }, 500); return () => clearInterval(intervalId); }, [])
ここでは React が使用されており、このロジックすべてをカスタム フックにラップできます。
import { useEffect } from 'react'; 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 フック
を使用できるようになります。メモリのリークについてですが、これも抽象化の利点です。setTimeout について説明しました。次に、addEventListener を見てみましょう。
この例では、キーボード ショートカット関数を作成します。さまざまなページにさまざまな機能があるため、さまざまなショートカット キー機能が作成されます。function homeShortcuts({ key}) { if (key === 'E') { console.log('edit widget') } } // 用户在主页上登陆,我们执行 document.addEventListener('keyup', homeShortcuts); // 用户做一些事情,然后导航到设置 function settingsShortcuts({ key}) { if (key === 'E') { console.log('edit setting') } } // 用户在主页上登陆,我们执行 document.addEventListener('keyup', 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 === &#39;E&#39;) {
console.log(&#39;edit widget&#39;)
}
}
// user lands on home and we execute
document.addEventListener(&#39;keyup&#39;, homeShortcuts);
// user does some stuff and navigates to settings
function settingsShortcuts({ key}) {
if (key === &#39;E&#39;) {
console.log(&#39;edit setting&#39;)
}
}
// user lands on home and we execute
document.removeEventListener(&#39;keyup&#39;, homeShortcuts);
document.addEventListener(&#39;keyup&#39;, settingsShortcuts);</pre><div class="contentsignin">ログイン後にコピー</div></div>
経験によれば、from を使用する場合は、グローバル オブジェクト ツールを使用する場合は、細心の注意を払ってください。
3.Observers
は、多くの開発者が知らないブラウザの Web API 関数です。これは、HTML 要素の可視性やサイズの変更を確認する場合に強力です。 尽管它很强大,但我们也要谨慎的使用它。一旦完成了对对象的观察,就要记得在不用的时候取消它。 看看代码: 上面的代码看起来不错。然而,一旦组件被卸载,观察者会发生什么?它不会被清除,那内存可就泄漏了。我们怎么解决这个问题呢?只需要使用 4. Window Object 向 Window 添加对象是一个常见的错误。在某些场景中,可能很难找到它,特别是在使用 Window Execution上下文中的 它看起来无害,但这取决于你从哪个上下文调用 另一个问题可能是错误地定义了一个全局变量: 要防止这种问题可以使用严格模式: 通过使用严格模式,向JavaScript编译器暗示,你想保护自己免受这些行为的影响。当你需要时,你仍然可以使用Window。不过,你必须以明确的方式使用它。 严格模式是如何影响我们前面的例子: 5. 持有DOM引用 DOM节点也不能避免内存泄漏。我们需要注意不要保存它们的引用。否则,垃圾回收器将无法清理它们,因为它们仍然是可访问的。 用一小段代码演示一下: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]);
this
关键字。看看下面的例子:function addElement(element) {
if (!this.stack) {
this.stack = {
elements: []
}
}
this.stack.elements.push(element);
}
addElement
。如果你从Window Context调用addElement,那就会越堆越多。var a = 'example 1'; // 作用域限定在创建var的地方
b = 'example 2'; // 添加到Window对象中
"use strict"
addElement
函数,当从全局作用域调用时,this
是未定义的const | let | var
,你会得到以下错误:Uncaught ReferenceError: b is not defined
const elements = [];
const list = document.getElementById('list');
function addElement() {
// clean nodes
list.innerHTML = '';
const divElement= document.createElement('div');
const element = document.createTextNode(`adding element ${elements.length}`);
divElement.appendChild(element);
list.appendChild(divElement);
elements.push(divElement);
}
document.getElementById('addElement').onclick = addElement;
注意,addElement
函数清除列表 div
,并将一个新元素作为子元素添加到它中。这个新创建的元素被添加到 elements
数组中。
下一次执行 addElement
时,该元素将从列表 div
中删除,但是它不适合进行垃圾收集,因为它存储在 elements
数组中。
我们在执行几次之后监视函数:
在上面的截图中看到节点是如何被泄露的。那怎么解决这个问题?清除 elements
数组将使它们有资格进行垃圾收集。
总结
在这篇文章中,我们已经看到了最常见的内存泄露方式。很明显,JavaScript本身并没有泄漏内存。相反,它是由开发者方面无意的内存保持造成的。只要代码是整洁的,而且我们不忘自己清理,就不会发生泄漏。
了解内存和垃圾回收在JavaScript中是如何工作的是必须的。一些开发者得到了错误的意识,认为由于它是自动的,所以他们不需要担心这个问题。
原文地址:https://betterprogramming.pub/5-common-javascript-memory-mistakes-c8553972e4c2
作者: Jose Granja
译者:前端小智
【相关推荐:javascript学习教程】
以上がJS でのメモリ リークを防ぐにはどうすればよいですか?よくある 5 つの記憶エラーについて話しましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

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

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

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

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

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

ホットトピック









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

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

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

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

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

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

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

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