开发者社区> lovejava> 正文

不懂JavaScript 内存管理的前端不是好程序员!

简介: 不懂JavaScript 内存管理的前端不是好程序员!
+关注继续查看

一位客户报告说,当点击一个按钮后,Chrome关闭了该页面,该页面就失去了响应。我最初认为这可能是Chrome扩展的问题。所以,我在隐身模式下进行了测试,但问题也在隐身模式下重现。


在解决这个问题之后,我花了很多时间阅读和理解JavaScript及其编译器。


因此就有了该篇文章


内存泄漏

内存泄漏是因为不需要的内存,但由于某种原因,它没有被回收返回到内存池。


JavaScript的设计方式是,一旦变量被使用,它将自动删除分配的内存,这个过程称为垃圾收集。


JavaScript编译器使用两种不同的垃圾收集器,一种是主Major GC,另一种是Minor GC。


更多: https://v8.dev/blog/trash-talk


Major GC: Major GC从整个堆中收集垃圾。


Minor GC: 小GC收集年轻代的垃圾。


Major GC:

主GC是主垃圾收集器,它识别活对象和死对象,并删除死对象。但是Major GC是在主线程上运行的,所以如果经常调用GC,页面就会变得无响应。


垃圾回收为什么冻结页面?


Garage collector运行在主线路上,所以它会阻塞所有用户输入,因此页面变得无响应。


好吧,但为什么主线程阻塞所有用户输入?


简单的回答是事件循环。更详细的答案,你需要看这个视频。对事件循环和JavaScript编译器有更详细的解释。


更多:https://www.youtube.com/watch?v=8aGhZQkoFbQ


改善应用程序内存管理的通用建议

1. 全局变量

垃圾收集器从不收集全局变量的内存,因此在开始声明全局变量之前,请三思。

但有时,我们会不小心引入了一个全局变量。


请看代码

function foo(arg) { 
    bar = "this is a hidden global variable";
}

您可能会注意到,该变量没有定义但赋值,因此它将成为一个全局变量。

这里,我们泄漏了一个字符串内存,你可能认为这不会产生大问题,但它会覆盖其他一些全局方法,这会引起新的隐患。


2. 引用没法回收

当涉及到对象和数据绑定时,一定要关注内存。

function run(){
  var domObjects = $(".myClass");
  domObjects.click(function(){
    domObjects.addClass(".myOtherClass");
  });
}


一旦函数被调用,JavaScript将删除分配的内存。但是在上面的代码中,GC没有办法收集“domObjects”的内存,因为它绑定到了事件监听器。


如果你想删除这些引用,你可以手动删除它们。

function run(){
  var domObjects = $(".myClass");
  domObjects.click(function(){
    if(domObjects){
      domObjects.addClass(".myOtherClass");
      domObjects = null;
    }
  });
}

3. 字符串连接

这听起来很奇怪,但是字符串连接需要额外的内存。因此,避免字符串连接,而使用模板字面量代替。


33.png


4. 避免创建新对象

新的内存被分配给新的对象、数组等。想办法减少这种情况。


让我们看一个jQuery的例子,


当你从不使用jQuery时,它会增加堆中的内存,所以我们可以避免使用jQuery链接方法。


44.png


6. JSON Parse

当您的应用程序在页面加载期间基于JSON进行渲染时,请考虑使用JSON.stringify和JSON.parse来处理这些数据。

22.png

更多: https://v8.dev/blog/cost-of-javascript-2019#json


7. 避免 try-catch

Try-catch比if分配更多的内存。但是try-catch对于大多数应用程序都是必要的,如果你分析得当,你可以把它们变成try-catch。


11.png

00.png

请看看下面链接中的问题,由node js环境中的try-catch引起的内存泄漏问题。您将获得一些关于try-catch和内存泄漏的知识


https://github.com/nodejs/node/issues/35048


8. 创建新窗口

当创建一个新窗口时,请把废弃的window引用设置为null。


当关闭窗口时,只调用Minor GC,因此只清除年轻代内存块。


如果您想检查JSHeap内存占用情况,请在您的控制台上输入此代码:

memory.usedJSHeapSize

。。.png


9. Callbacks回调

如果事件的回调频率非常高,考虑避免它。让我们以滚动为例。当您将滚动事件绑定到窗口用户向下/向上滚动时,回调调用的频率非常高。


可以使用 Underscore.js 中 _.throttle 和 _.debounce 来减少回调执行,避免页面卡顿。

function log( event ) {
  console.log( $(window).scrollTop(), event.timeStamp );
};
// 控制台记录窗口滚动事件,触发频率比你想象的要快
$(window).scroll( log );
// 控制台记录窗口滚动事件,每250ms最多触发一次
$(window).scroll( _.throttle( log, 250 ) );
function ajax_lookup( event ) {
  // 对输入的内容$(this).val()执行 Ajax 查询
};
// 字符输入的频率比你预想的要快,Ajax 请求来不及回复。
$('input:text').keyup( ajax_lookup );
// 当用户停顿250毫秒以后才开始查找
$('input:text').keyup( _.debounce( ajax_lookup, 250 ) );

更多请阅读https://blog.coding.net/blog/the-difference-between-throttle-and-debounce-in-underscorejs

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
网站介绍web前端 html+css+javascript网页设计
网站介绍web前端 html+css+javascript网页设计
11 0
前端学习案例1-什么是js表达式
前端学习案例1-什么是js表达式
12 0
云his系统源码 前端由Angular语言、JavaScript+后端Java语言开发
基层卫生健康云HIS系统采用云端SaaS服务的方式提供,使用用户通过浏览器即能访问,无需关注系统的部署、维护、升级等问题,系统充分考虑了模板化、配置化、智能化、扩展化等设计方法,覆盖了基层医疗机构的主要工作流程,能够与监管系统有序对接,并能满足未来系统扩展的需要。 适用于二级医院、基层医疗机构,可作为区域HIS使用,经扩展后能够应用于医联体/医共体。融合B/S版电子病历系统,支持电子病历四级,HIS与电子病历系统均拥有自主知识产权。
45 0
前端 js 将字符串类型转换成其他类型
前端 js 将字符串类型转换成其他类型
9 0
一个注册页面的前端模板(html+css+javascript)可自适应屏幕
一个注册页面的前端模板(html+css+javascript)可自适应屏幕,修改样式即可用。
16 0
重学前端 33 # JavaScript表达式的右边部分
重学前端 33 # JavaScript表达式的右边部分
18 0
重学前端 32 # JavaScript的表达式语句
重学前端 32 # JavaScript的表达式语句
15 0
重学前端 31 # JavaScript的语句
重学前端 31 # JavaScript的语句
10 0
重学前端 30 # JavaScript语法的基本规则
重学前端 30 # JavaScript语法的基本规则
17 0
重学前端 29 # JavaScript中要不要加分号?
重学前端 29 # JavaScript中要不要加分号?
13 0
+关注
文章
问答
文章排行榜
最热
最新
相关电子书
更多
Javascript异步编程
立即下载
Javascript中的对象
立即下载
JS零基础入门教程(上册)
立即下载