5 つの一般的な JavaScript メモリ エラー
JavaScript 学習チュートリアル]ガベージ コレクションを強制することはできないので、ガベージ コレクションが適切に機能することをどのように確認すればよいでしょうか?私たちはそれについてどれくらい知っていますか?
このプロセス中はスクリプトの実行が一時停止されます
- アクセスできないリソースのメモリが解放されます
- 未定義です
- メモリ全体をチェックするわけではありません
- これは予測不可能ですが、必要に応じて実行されます
- これは、リソースとメモリの分散の問題を心配する必要がないことを意味しますか? もちろんそうではありません。注意しないと、メモリ リークが発生する可能性があります。
#メモリ リークとは何ですか?
#メモリ リークとは、ソフトウェアによって再利用できない、割り当てられたメモリのブロックです。
Javascript はガベージ コレクターを提供しますが、これはメモリ リークを回避できることを意味するものではありません。ガベージ コレクションの対象となるには、オブジェクトが他の場所で参照されていてはなりません。未使用のリソースへの参照を保持すると、それらのリソースが再利用されなくなります。これは、無意識の記憶保持と呼ばれます。
メモリのリークにより、ガベージ コレクターがより頻繁に実行される可能性があります。このプロセスによりスクリプトの実行が妨げられるため、プログラムがフリーズする可能性があります。このような遅延が発生すると、うるさいユーザーは、満足できない場合は製品が長時間オフラインになることに間違いなく気づくでしょう。さらに深刻なことに、アプリケーション全体がクラッシュする可能性があります。これは gg です。 メモリ リークを防ぐにはどうすればよいでしょうか? 重要なのは、不必要なリソースを保持しないようにすることです。いくつかの一般的なシナリオを見てみましょう。
1. タイマー監視setInterval() メソッドは、一定の間隔で関数を呼び出すか、コード フラグメントを実行します。遅れ。間隔を一意に識別する間隔
ID が返されるため、後で clearInterval()
を呼び出して削除できます。 # ループの後に完了したことを示すコールバック関数を呼び出すコンポーネントを作成します。この例では React を使用していますが、これはどの FE フレームワークでも機能します。
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">import React, { useRef } from 'react';
const Timer = ({ cicles, onFinish }) => {
const currentCicles = useRef(0);
setInterval(() => {
if (currentCicles.current >= cicles) {
onFinish();
return;
}
currentCicles.current++;
}, 500);
return (
<p>Loading ...</p>
);
}
export default Timer;</pre><div class="contentsignin">ログイン後にコピー</div></div>
一見すると問題ないようです。心配しないで、このタイマーをトリガーする別のコンポーネントを作成し、そのメモリ パフォーマンスを分析しましょう。
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 ( <p> {showTimer ? ( <timer></timer> ): ( <button> setShowTimer(true)}> Retry </button> )} </p> ) }
Retry
ボタンを数回クリックした後、Chrome デベロッパー ツールを使用してメモリ使用量を取得した結果が次のとおりです:
再試行ボタンをクリックすると、より多くのメモリが割り当てられることがわかります。これは、以前に割り当てられたメモリが解放されていないことを意味します。タイマーは交換されずにまだ動作しています。
setInterval の戻り値は間隔 ID であり、この間隔をキャンセルするために使用できます。この特定のケースでは、コンポーネントがアンロードされた後に
を呼び出すことができます。
useEffect(() => { const intervalId = setInterval(() => { if (currentCicles.current >= cicles) { onFinish(); return; } currentCicles.current++; }, 500); return () => clearInterval(intervalId); }, [])
コードを作成するときにこの問題を見つけるのが難しい場合がありますが、最善の方法はコンポーネントを抽象化することです。 ここでは React が使用されており、このロジックすべてをカスタム フックにラップできます。
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">import { useEffect } from 'react';
export const useTimeout = (refreshCycle = 100, callback) => {
useEffect(() => {
if (refreshCycle {
callback();
}, refreshCycle);
return () => clearInterval(intervalId);
}, [refreshCycle, setInterval, clearInterval]);
};
export default useTimeout;</pre><div class="contentsignin">ログイン後にコピー</div></div>
を使用する必要がある場合は、次のようにすることができます:
const handleTimeout = () => ...; useTimeout(100, handleTimeout);
これで、心配することなく、この
useTimeout フック を使用できるようになります。メモリのリークについてですが、これも抽象化の利点です。
Web API は多数のイベント リスナーを提供します。前に、
について説明しました。次に、addEventListener を見てみましょう。
この例では、キーボード ショートカット関数を作成します。さまざまなページにさまざまな機能があるため、さまざまなショートカット キー機能が作成されます。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">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);</pre><div class="contentsignin">ログイン後にコピー</div></div>
は、2 番目の addEventListener
を実行する前にクリーンアップがないことを除けば、問題ないようです。
keyup
リスナーを置き換えるのではなく、別のcallback を追加します。これは、キーが押されると 2 つの機能がトリガーされることを意味します。
前のコールバックをクリアするには、
removeEventListener :
document.removeEventListener(‘keyup’, homeShortcuts);
上記のコードをリファクタリングする必要があります:
function homeShortcuts({ key}) { if (key === 'E') { console.log('edit widget') } } // user lands on home and we execute document.addEventListener('keyup', homeShortcuts); // user does some stuff and navigates to settings function settingsShortcuts({ key}) { if (key === 'E') { console.log('edit setting') } } // user lands on home and we execute document.removeEventListener('keyup', homeShortcuts); document.addEventListener('keyup', settingsShortcuts);
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 = 'example 1'; // 作用域限定在创建var的地方 b = 'example 2'; // 添加到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('list'); function addElement() { // clean nodes list.innerHTML = ''; const pElement= document.createElement('p'); const element = document.createTextNode(`adding element ${elements.length}`); pElement.appendChild(element); list.appendChild(pElement); elements.push(pElement); } document.getElementById('addElement').onclick = addElement;
注意,addElement
函数清除列表 p
,并将一个新元素作为子元素添加到它中。这个新创建的元素被添加到 elements
数组中。
下一次执行 addElement
时,该元素将从列表 p
中删除,但是它不适合进行垃圾收集,因为它存储在 elements
数组中。
我们在执行几次之后监视函数:
在上面的截图中看到节点是如何被泄露的。那怎么解决这个问题?清除 elements
数组将使它们有资格进行垃圾收集。
总结
在这篇文章中,我们已经看到了最常见的内存泄露方式。很明显,JavaScript本身并没有泄漏内存。相反,它是由开发者方面无意的内存保持造成的。只要代码是整洁的,而且我们不忘自己清理,就不会发生泄漏。
了解内存和垃圾回收在JavaScript中是如何工作的是必须的。一些开发者得到了错误的意识,认为由于它是自动的,所以他们不需要担心这个问题。
作者: Jose Granja
原文:https://betterprogramming.pub/5-common-javascript-memory-mistakes-c8553972e4c2
(学习视频分享:web前端)
以上が5 つの一般的な JavaScript メモリ エラーの詳細内容です。詳細については、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)

ホットトピック









PHP と Vue: フロントエンド開発ツールの完璧な組み合わせ 今日のインターネットの急速な発展の時代において、フロントエンド開発はますます重要になっています。 Web サイトやアプリケーションのエクスペリエンスに対するユーザーの要求がますます高まっているため、フロントエンド開発者は、より効率的で柔軟なツールを使用して、応答性の高いインタラクティブなインターフェイスを作成する必要があります。フロントエンド開発の分野における 2 つの重要なテクノロジーである PHP と Vue.js は、組み合わせることで完璧なツールと見なされます。この記事では、PHP と Vue の組み合わせと、読者がこれら 2 つをよりよく理解し、適用できるようにするための詳細なコード例について説明します。

フロントエンド開発のインタビューでは、HTML/CSS の基本、JavaScript の基本、フレームワークとライブラリ、プロジェクトの経験、アルゴリズムとデータ構造、パフォーマンスの最適化、クロスドメイン リクエスト、フロントエンド エンジニアリング、デザインパターン、新しいテクノロジーとトレンド。面接官の質問は、候補者の技術スキル、プロジェクトの経験、業界のトレンドの理解を評価するように設計されています。したがって、候補者はこれらの分野で自分の能力と専門知識を証明するために十分な準備をしておく必要があります。

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

Django は、迅速な開発とクリーンなメソッドを重視した Python で書かれた Web アプリケーション フレームワークです。 Django は Web フレームワークですが、Django がフロントエンドなのかバックエンドなのかという質問に答えるには、フロントエンドとバックエンドの概念を深く理解する必要があります。フロントエンドはユーザーが直接対話するインターフェイスを指し、バックエンドはサーバー側プログラムを指し、HTTP プロトコルを通じてデータと対話します。フロントエンドとバックエンドが分離されている場合、フロントエンドとバックエンドのプログラムをそれぞれ独立して開発して、ビジネス ロジックとインタラクティブ効果、およびデータ交換を実装できます。

Go 言語は、高速で効率的なプログラミング言語として、バックエンド開発の分野で広く普及しています。ただし、Go 言語をフロントエンド開発と結びつける人はほとんどいません。実際、フロントエンド開発に Go 言語を使用すると、効率が向上するだけでなく、開発者に新たな視野をもたらすことができます。この記事では、フロントエンド開発に Go 言語を使用する可能性を探り、読者がこの分野をよりよく理解できるように具体的なコード例を示します。従来のフロントエンド開発では、ユーザー インターフェイスの構築に JavaScript、HTML、CSS がよく使用されます。

Golang とフロントエンド テクノロジーの組み合わせ: Golang がフロントエンド分野でどのような役割を果たしているかを調べるには、具体的なコード例が必要です。インターネットとモバイル アプリケーションの急速な発展に伴い、フロントエンド テクノロジーの重要性がますます高まっています。この分野では、強力なバックエンド プログラミング言語としての Golang も重要な役割を果たします。この記事では、Golang がどのようにフロントエンド テクノロジーと組み合わされるかを検討し、具体的なコード例を通じてフロントエンド分野での可能性を実証します。フロントエンド分野における Golang の役割は、効率的で簡潔かつ学びやすいものとしてです。

Django: フロントエンド開発とバックエンド開発の両方を処理できる魔法のフレームワークです。 Django は、効率的でスケーラブルな Web アプリケーション フレームワークです。 MVCやMTVなど複数のWeb開発モデルをサポートし、高品質なWebアプリケーションを簡単に開発できます。 Django はバックエンド開発をサポートするだけでなく、フロントエンド インターフェイスを迅速に構築し、テンプレート言語を通じて柔軟なビュー表示を実現します。 Django はフロントエンド開発とバックエンド開発をシームレスに統合するため、開発者は学習に特化する必要がありません。

JavaScript で HTTP ステータス コードを取得する方法の紹介: フロントエンド開発では、バックエンド インターフェイスとの対話を処理する必要があることが多く、HTTP ステータス コードはその非常に重要な部分です。 HTTP ステータス コードを理解して取得すると、インターフェイスから返されたデータをより適切に処理できるようになります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法と、具体的なコード例を紹介します。 1. HTTP ステータス コードとは何ですか? HTTP ステータス コードとは、ブラウザがサーバーへのリクエストを開始したときに、サービスが
