JavaScript does not provide any memory management operations. Instead, memory is managed by the JavaScript VM through a memory reclamation process called garbage collection. [Related recommendations: javascript learning tutorial]Since we can’t force garbage collection, how do we know it can work properly? How much do we know about it?
Script execution is paused during this process- It releases memory for inaccessible resources
- It is undefined
- It does not Checking the entire memory at once instead running over multiple cycles
- It is unpredictable but it will do it when necessary
- Does this mean no need to worry about resources and memory Distribution issue? Of course not. If we are not careful, some memory leaks may occur.
A memory leak is a block of allocated memory that cannot be reclaimed by software.
Javascript provides a garbage collector, but this does not mean that we can avoid memory leaks. To be eligible for garbage collection, the object must not be referenced elsewhere. If you hold references to unused resources, this will prevent those resources from being reclaimed. This is called
unconscious memory retention. Leaking memory may cause the garbage collector to run more frequently. Since this process will prevent the script from running, it may cause our program to freeze. If such a lag occurs, picky users will definitely notice that if they are not happy with it, the product will be offline for a long time. More seriously, it may cause the entire application to crash, which is gg.
How to prevent memory leaks? The main thing is that we should avoid retaining unnecessary resources. Let’s look at some common scenarios.
1. Timer monitoringsetInterval()
method repeatedly calls a function or executes a code fragment, with a fixed interval between each call time delay. It returns an interval ID
that uniquely identifies the interval so you can later delete it by calling clearInterval()
. We create a component that calls a callback function to indicate that it is complete after
x
loops. I'm using React in this example, but this works with any FE framework.
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;
At first glance, there seems to be no problem. Don't worry, let's create another component that triggers this timer and analyze its memory performance. <pre class="brush:php;toolbar:false">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>
????)
}</pre>
After a few clicks on the
button, this is the result of using Chrome Dev Tools to get the memory usage:
how to solve this problem? The return value of
is an interval ID, which we can use to cancel this interval. In this particular case, we can call
clearInterval after the component is unloaded. <pre class="brush:php;toolbar:false">useEffect(()?=>?{
????const?intervalId?=?setInterval(()?=>?{
????????if?(currentCicles.current?>=?cicles)?{
????????????onFinish();
????????????return;
????????}
????????currentCicles.current++;
????},?500);
????return?()?=>?clearInterval(intervalId);
},?[])</pre>
Sometimes, it is difficult to find this problem when writing code. The best way is to abstract the components. React is used here, and we can wrap all this logic in a custom Hook.
import?{?useEffect?}?from?'react'; export?const?useTimeout?=?(refreshCycle?=?100,?callback)?=>?{ ????useEffect(()?=>?{ ????????if?(refreshCycle??{ ????????????callback(); ????????},?refreshCycle); ????????return?()?=>?clearInterval(intervalId); ????},?[refreshCycle,?setInterval,?clearInterval]); }; export?default?useTimeout;
Now when you need to use
setInterval, you can do this:
const?handleTimeout?=?()?=>?...; useTimeout(100,?handleTimeout);
Now you can use this useTimeout Hook
without having to worry about the memory being Leak, this is also the benefit of abstraction.
2. Event listening
Web API provides a large number of event listeners. Earlier, we discussed setTimeout. Now let’s take a look at
addEventListener. In this case, we create a keyboard shortcut function. Since we have different functions on different pages, different shortcut key functions will be created
<pre class="brush:php;toolbar:false">function?homeShortcuts({?key})?{
????if?(key?===?'E')?{
????????console.log('edit?widget')
????}
}
//?用戶在主頁上登陸,我們執(zhí)行
document.addEventListener('keyup',?homeShortcuts);?
//?用戶做一些事情,然后導(dǎo)航到設(shè)置
function?settingsShortcuts({?key})?{
????if?(key?===?'E')?{
????????console.log('edit?setting')
????}
}
//?用戶在主頁上登陸,我們執(zhí)行
document.addEventListener('keyup',?settingsShortcuts);</pre>
still looks fine except there is no cleanup before when executing the second
The
keyup. Rather than replacing our keyup
listener, this code will add another callback
. This means that when a key is pressed, it triggers two functions. To clear the previous callback, we need to use
removeEventListener
:
document.removeEventListener(‘keyup’,?homeShortcuts);
Refactor the above code: <pre class="brush:php;toolbar:false">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);</pre>
According to experience, when using from Be extremely careful when working with global object tools.
Observers is a browser’s Web API function that many developers don’t know about. This is powerful if you want to check for changes in visibility or size of HTML elements.
IntersectionObserver
接口 (從屬于Intersection Observer API) 提供了一種異步觀察目標(biāo)元素與其祖先元素或頂級(jí)文檔視窗(viewport
)交叉狀態(tài)的方法。祖先元素與視窗(viewport
)被稱為根(root
)。
盡管它很強(qiáng)大,但我們也要謹(jǐn)慎的使用它。一旦完成了對(duì)對(duì)象的觀察,就要記得在不用的時(shí)候取消它。
看看代碼:
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]);
上面的代碼看起來不錯(cuò)。然而,一旦組件被卸載,觀察者會(huì)發(fā)生什么?它不會(huì)被清除,那內(nèi)存可就泄漏了。我們?cè)趺唇鉀Q這個(gè)問題呢?只需要使用 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 添加對(duì)象是一個(gè)常見的錯(cuò)誤。在某些場(chǎng)景中,可能很難找到它,特別是在使用 Window Execution上下文中的this
關(guān)鍵字。看看下面的例子:
function?addElement(element)?{ ????if?(!this.stack)?{ ????????this.stack?=?{ ????????????elements:?[] ????????} ????} ????this.stack.elements.push(element); }
它看起來無害,但這取決于你從哪個(gè)上下文調(diào)用addElement
。如果你從Window Context調(diào)用addElement,那就會(huì)越堆越多。
另一個(gè)問題可能是錯(cuò)誤地定義了一個(gè)全局變量:
var?a?=?'example?1';?//?作用域限定在創(chuàng)建var的地方 b?=?'example?2';?//?添加到Window對(duì)象中
要防止這種問題可以使用嚴(yán)格模式:
"use?strict"
通過使用嚴(yán)格模式,向JavaScript編譯器暗示,你想保護(hù)自己免受這些行為的影響。當(dāng)你需要時(shí),你仍然可以使用Window。不過,你必須以明確的方式使用它。
嚴(yán)格模式是如何影響我們前面的例子:
- 對(duì)于
addElement
函數(shù),當(dāng)從全局作用域調(diào)用時(shí),this
是未定義的 - 如果沒有在一個(gè)變量上指定
const | let | var
,你會(huì)得到以下錯(cuò)誤:
Uncaught?ReferenceError:?b?is?not?defined
5. 持有DOM引用
DOM節(jié)點(diǎn)也不能避免內(nèi)存泄漏。我們需要注意不要保存它們的引用。否則,垃圾回收器將無法清理它們,因?yàn)樗鼈內(nèi)匀皇强稍L問的。
用一小段代碼演示一下:
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
函數(shù)清除列表 p
,并將一個(gè)新元素作為子元素添加到它中。這個(gè)新創(chuàng)建的元素被添加到 elements
數(shù)組中。
下一次執(zhí)行 addElement
時(shí),該元素將從列表 p
中刪除,但是它不適合進(jìn)行垃圾收集,因?yàn)樗鎯?chǔ)在 elements
數(shù)組中。
我們?cè)趫?zhí)行幾次之后監(jiān)視函數(shù):
在上面的截圖中看到節(jié)點(diǎn)是如何被泄露的。那怎么解決這個(gè)問題?清除 elements
?數(shù)組將使它們有資格進(jìn)行垃圾收集。
總結(jié)
在這篇文章中,我們已經(jīng)看到了最常見的內(nèi)存泄露方式。很明顯,JavaScript本身并沒有泄漏內(nèi)存。相反,它是由開發(fā)者方面無意的內(nèi)存保持造成的。只要代碼是整潔的,而且我們不忘自己清理,就不會(huì)發(fā)生泄漏。
了解內(nèi)存和垃圾回收在JavaScript中是如何工作的是必須的。一些開發(fā)者得到了錯(cuò)誤的意識(shí),認(rèn)為由于它是自動(dòng)的,所以他們不需要擔(dān)心這個(gè)問題。
作者: Jose Granja?
原文:https://betterprogramming.pub/5-common-javascript-memory-mistakes-c8553972e4c2
(學(xué)習(xí)視頻分享:web前端)
The above is the detailed content of 5 common JavaScript memory errors. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

PHP and Vue: a perfect pairing of front-end development tools. In today's era of rapid development of the Internet, front-end development has become increasingly important. As users have higher and higher requirements for the experience of websites and applications, front-end developers need to use more efficient and flexible tools to create responsive and interactive interfaces. As two important technologies in the field of front-end development, PHP and Vue.js can be regarded as perfect tools when paired together. This article will explore the combination of PHP and Vue, as well as detailed code examples to help readers better understand and apply these two

As a fast and efficient programming language, Go language is widely popular in the field of back-end development. However, few people associate Go language with front-end development. In fact, using Go language for front-end development can not only improve efficiency, but also bring new horizons to developers. This article will explore the possibility of using the Go language for front-end development and provide specific code examples to help readers better understand this area. In traditional front-end development, JavaScript, HTML, and CSS are often used to build user interfaces

Django is a web application framework written in Python that emphasizes rapid development and clean methods. Although Django is a web framework, to answer the question whether Django is a front-end or a back-end, you need to have a deep understanding of the concepts of front-end and back-end. The front end refers to the interface that users directly interact with, and the back end refers to server-side programs. They interact with data through the HTTP protocol. When the front-end and back-end are separated, the front-end and back-end programs can be developed independently to implement business logic and interactive effects respectively, and data exchange.

In front-end development interviews, common questions cover a wide range of topics, including HTML/CSS basics, JavaScript basics, frameworks and libraries, project experience, algorithms and data structures, performance optimization, cross-domain requests, front-end engineering, design patterns, and new technologies and trends. . Interviewer questions are designed to assess the candidate's technical skills, project experience, and understanding of industry trends. Therefore, candidates should be fully prepared in these areas to demonstrate their abilities and expertise.

Django: A magical framework that can handle both front-end and back-end development! Django is an efficient and scalable web application framework. It is able to support multiple web development models, including MVC and MTV, and can easily develop high-quality web applications. Django not only supports back-end development, but can also quickly build front-end interfaces and achieve flexible view display through template language. Django combines front-end development and back-end development into a seamless integration, so developers don’t have to specialize in learning

Combination of Golang and front-end technology: To explore how Golang plays a role in the front-end field, specific code examples are needed. With the rapid development of the Internet and mobile applications, front-end technology has become increasingly important. In this field, Golang, as a powerful back-end programming language, can also play an important role. This article will explore how Golang is combined with front-end technology and demonstrate its potential in the front-end field through specific code examples. The role of Golang in the front-end field is as an efficient, concise and easy-to-learn

React's main functions include componentized thinking, state management and virtual DOM. 1) The idea of ??componentization allows splitting the UI into reusable parts to improve code readability and maintainability. 2) State management manages dynamic data through state and props, and changes trigger UI updates. 3) Virtual DOM optimization performance, update the UI through the calculation of the minimum operation of DOM replica in memory.

The difference: The front end is responsible for user interface design and interaction, including web pages, images, and other content that users see in the browser. The backend is responsible for processing data and performing logical operations, including server-side scripts, databases, and APIs.
