返回顶部
首页 > 资讯 > 精选 >常见的JavaScript内存错误怎么解决
  • 888
分享到

常见的JavaScript内存错误怎么解决

2023-06-22 07:06:49 888人浏览 泡泡鱼
摘要

这篇文章主要介绍“常见的javascript内存错误怎么解决”,在日常操作中,相信很多人在常见的JavaScript内存错误怎么解决问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”常见的JavaScript内存

这篇文章主要介绍“常见的javascript内存错误怎么解决”,在日常操作中,相信很多人在常见的JavaScript内存错误怎么解决问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”常见的JavaScript内存错误怎么解决”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

前言:

JavaScript 不提供任何内存管理操作。相反,内存由 JavaScript VM 通过内存回收过程管理,该过程称为垃圾收集。

既然我们不能强制的垃圾回收,那我们怎么知道它能正常工作?我们对它又了解多少呢?

脚本执行在此过程中暂停
它为不可访问的资源释放内存
它是不确定的
它不会一次检查整个内存,而是在多个周期中运行
它是不可预测的,但它会在必要时执行
这是否意味着无需担心资源和内存分配问题?当然不是。如果我们一不小心,可能会产生一些内存泄漏。

什么是内存泄漏?

内存泄漏是软件无法回收的已分配的内存块。

Javascript 提供了一个垃圾收集程序,但这并不意味着我们就能避免内存泄漏。为了符合垃圾收集的条件,该对象必须不被其他地方引用。如果持有对未使用的资源的引用,这将会阻止这些资源被回收。这就是所谓的无意识的内存保持。

泄露内存可能会导致垃圾收集器更频繁地运行。由于这个过程会阻止脚本的运行,它可能会让我们程序卡起来,这么一卡,挑剔的用户肯定会注意到,一用不爽了,那这个产品离下线的日子就不完了。更严重可能会让整个应用奔溃,那就gg了。

如何防止内存泄漏? 主要还是我们应该避免保留不必要的资源。来看看一些常见的场景。

1.计时器的监听

setInterval() 方法重复调用函数或执行代码片段,每次调用之间有固定的时间延迟。它返回一个时间间隔ID,该ID唯一地标识时间间隔,因此您可以稍后通过调用 clearInterval() 来删除它。

我们创建一个组件,它调用一个回调函数来表示它在x个循环之后完成了。我在这个例子中使用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 Dev Tools获取内存使用的结果:

常见的JavaScript内存错误怎么解决

当我们点击重试按钮时,可以看到分配的内存越来越多。这说明之前分配的内存没有被释放。计时器仍然在运行而不是被替换。

怎么解决这个问题?setInterval 的返回值是一个间隔 ID,我们可以用它来取消这个间隔。在这种特殊情况下,我们可以在组件卸载后调用 clearInterval

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

有时,在编写代码时,很难发现这个问题,最好的方式,还是要把组件抽象化。

这里使用的是React,我们可以把所有这些逻辑都包装在一个自定义的 Hook 中。

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 Hook,而不必担心内存被泄露,这也是抽象化的好处。

2.事件监听

WEB api提供了大量的事件监听器。在前面,我们讨论了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);

看起来还是很好,除了在执行第二个 addEventListener 时没有清理之前的 keyup。这段代码不是替换我们的 keyup 监听器,而是将添加另一个 callback。这意味着,当一个键被按下时,它将触发两个函数。

要清除之前的回调,我们需要使用 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 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 数组中。

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

5个常见的JavaScript内存错误

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

到此,关于“常见的JavaScript内存错误怎么解决”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: 常见的JavaScript内存错误怎么解决

本文链接: https://lsjlt.com/news/303230.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 常见的JavaScript内存错误怎么解决
    这篇文章主要介绍“常见的JavaScript内存错误怎么解决”,在日常操作中,相信很多人在常见的JavaScript内存错误怎么解决问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”常见的JavaScript内存...
    99+
    2023-06-22
  • 常见的JavaScript内存错误及解决方法
    目录1.计时器的监听2.事件监听3.Observers4. Window Object5. 持有DOM引用前言: JavaScript 不提供任何内存管理操作。相反,内存由 Java...
    99+
    2024-04-02
  • 常见的JavaScript内存错误有哪些
    本文小编为大家详细介绍“常见的JavaScript内存错误有哪些”,内容详细,步骤清晰,细节处理妥当,希望这篇“常见的JavaScript内存错误有哪些”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,...
    99+
    2024-04-02
  • JavaScript常见的五个内存错误是什么
    这篇文章主要介绍“JavaScript常见的五个内存错误是什么”,在日常操作中,相信很多人在JavaScript常见的五个内存错误是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JavaScript常见的...
    99+
    2023-06-26
  • JavaScript 内存管理陷阱:避免常见错误
    内存泄漏 内存泄漏是指 JavaScript 中分配的内存未被正确释放,导致应用程序累积大量未使用的内存。这可能会导致性能下降、浏览器崩溃甚至内存耗尽错误。 避免内存泄漏的策略: 确保元素不再被引用时释放它们:使用 null 或 und...
    99+
    2024-04-02
  • 带大家了解一下JavaScript常见的五个内存错误
    目录什么是内存泄漏?1.计时器的监听2.事件监听3.Observers4. Window Object5. 持有DOM引用总结JavaScript 不提供任何内存管理操作。相反,内存...
    99+
    2024-04-02
  • JavaScript开发中常见错误解决是怎样的
    JavaScript开发中常见错误解决是怎样的,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。身为一名前端打工人,当然是经验越多,在排查错误...
    99+
    2024-04-02
  • 常见的CDN配置错误怎么解决
    DNS解析错误:确保CDN配置中的域名正确解析到CDN服务商提供的IP地址。检查DNS记录是否正确配置,如果有问题,可以尝试重新...
    99+
    2024-04-24
    CDN
  • c语言详解动态内存分配及常见错误的解决
    目录为什么会有动态内存分配动态内存函数的介绍malloc freecallocrealloc常见的错误对NULL指针的解引用操作越界访问对非动态内存进行free使用free...
    99+
    2024-04-02
  • 讲解一些常见的JavaScript错误
    JavaScript是前端开发中不可或缺的一部分,它为网页提供了动态效果和交互性。但是,在开发的过程中难免会出现JavaScript错误,这些错误会引发各种问题,影响网站的正常运行。本文将从以下几个方面来讲解一些常见的JavaScript错...
    99+
    2023-05-14
  • C++ 函数内存分配的常见错误及其解决方法
    函数内存分配的常见错误包括:1) 裸指针悬垂;2) 内存泄漏;3) 野指针;4) 释放无效指针。解决方法:1) 使用智能指针;2) 使用raii;3) 使用内存池。 C++ 函数内存分...
    99+
    2024-04-22
    c++ 内存分配 作用域 内存占用
  • JavaScript错误处理的常见错误和陷阱
    在JavaScript开发中,错误处理是很重要的一个环节,错误处理一般通过try…catch语句来实现。try语句块中放置要执行的代码,catch语句块中放置要处理的异常。当try语句块中出现异常时,JavaScript引擎会自动执行ca...
    99+
    2024-02-27
    JavaScript 错误处理 try catch 异常
  • java常见错误有哪些及怎么解决
    Java常见错误有以下几种:1. 语法错误:比如拼写错误、缺少分号等。解决方法是检查代码中的拼写和语法错误,并进行修正。2. 运行时...
    99+
    2023-09-06
    java
  • JavaScript throw 语句的陷阱:常见错误和解决方案
    1. 缺少错误消息 错误: function divide(a, b) { if (b === 0) throw; // 缺少错误消息 } 解决方案:始终提供一个描述性错误消息,说明错误的性质。 function divide(a,...
    99+
    2024-03-01
    JavaScript, throw, 错误处理, 异常处理, 调试
  • phpmyadmin常见的错误和解决方法
    本篇文章给大家分享的是有关phpmyadmin常见的错误和解决方法,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1.phpmyadmin解决i...
    99+
    2024-04-02
  • nginx常见502错误的解决方法
    Nginx 502错误情况1: 网站的访问量大,而php-cgi的进程数偏少。 针对这种情况的502错误,只需增加php-cgi的进程数。具体就是修改/usr/local/php/etc/php-fpm.con...
    99+
    2023-09-09
    nginx 服务器 php Powered by 金山文档
  • JavaScript常见的错误处理方法
    这篇文章主要介绍“JavaScript常见的错误处理方法”,在日常操作中,相信很多人在JavaScript常见的错误处理方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Ja...
    99+
    2024-04-02
  • JavaScript中几个最常见的错误
    这篇文章主要介绍“JavaScript中几个最常见的错误”,在日常操作中,相信很多人在JavaScript中几个最常见的错误问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Ja...
    99+
    2024-04-02
  • JavaScript中常见的错误有哪些
    这篇文章主要讲解了“JavaScript中常见的错误有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JavaScript中常见的错误有哪些”吧!Java...
    99+
    2024-04-02
  • PHP常见错误及解决方法
    PHP作为一种非常流行的服务器端脚本语言,被广泛应用于Web开发。然而,在编写PHP代码时,常常会遇到一些错误,这些错误可能由语法错误、逻辑错误、运行时错误等引起。本文将针对常见的PH...
    99+
    2024-03-12
    解决方法 php错误 常见问题
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作