JavaScript 事件对内存和性能的影响


Posted in Javascript onJanuary 22, 2017

虽说事件处理程序可以为现代 Web 页面添加很强的交互能力,但是不分青红皂白就添加大量的事件处理程序绝对是一种愚蠢的行为。

我们来分析一下:事件处理程序本质上是一种函数,是一种对象,存放在内存中,设置大量的事件处理程序会使内存中的对象变多,Web 程序的性能会变得越来越差,用户体验很不好。

为了更好地利用好事件处理程序,便出现了事件委托,用来提升性能。

事件委托

事件委托(event delegation):把若干个子节点上的相同事件的处理函数绑定到它的父节点上去,在父节点上统一处理从子节点冒泡上来的事件,这种技术就叫做事件委托。

补充一下:事件委托并不局限于父节点与子节点之间。也可以这样玩,比如页面文档中有好多个处在不同位置地 button,都是绑定 click 事件,使用事件委托,我们可以把这些个事件统一绑定到 body 元素,然后再进行处理(虽然一般很少这么用)。

下面举例子逐步说明事件委托的优势:

<ul id="parent-list">
 <li id="list-1">List 1</li>
 <li id="list-2">List 2</li>
 <li id="list-3">List 3</li>
 <li id="list-4">List 4</li>
 <li id="list-5">List 5</li>
</ul>

假设有上面的代码,我们现在有一个需求:就是无论单击上面的列表(ul)的哪个子列表(li),都会弹出一个框,来显示我们点击了哪个子列表。

需求不难吧?有了需求,接下来是该写 js 代码了,现在有两种方法放在你眼前:1. 为每个 li 子元素绑定 click 事件,然后设置处理函数; 2. 利用事件委托,为 ul 父元素绑定 click 事件,然后设置处理函数

// 方法一
var list1 = document.getElementById("list-1");
list1.addEventListener("click",function(){
 alert(this.firstChild.nodeValue);
},false);
var list2 = document.getElementById("list-2");
list2.addEventListener("click", function() {
 alert(this.firstChild.nodeValue);
}, false);
var list3 = document.getElementById("list-3");
list3.addEventListener("click", function() {
 alert(this.firstChild.nodeValue);
}, false);
var list4 = document.getElementById("list-4");
list4.addEventListener("click", function() {
 alert(this.firstChild.nodeValue);
}, false);
var list5 = document.getElementById("list-5");
list5.addEventListener("click", function() {
 alert(this.firstChild.nodeValue);
}, false);
// 方法二
var parentList = document.getElementById("parent-list");
parentList.addEventListener("click",function(){
 var target = event.target;
 if(target.nodeName.toLowerCase() === "li"){
 alert(target.firstChild.nodeValue);
 }
},false);

看着上面的代码,我这里写几点方法二的优点:1. 减少了访问 DOM 的次数,提升了性能;2. 将子元素的事件处理程序统一绑定到其父元素,减少了对内存的占用;3. 可以更好地管理事件处理程序,比如移除对某个事件处理程序的引用

注意:如果对各个子元素的需求不一样,我们还可以这样来改写上面的方法二:

// 方法二
var parentList = document.getElementById("parent-list");
parentList.addEventListener("click",function(){
 var target = event.target;
 if(target.nodeName.toLowerCase() === "li"){
 switch(target.id){
  case "list-1":
  alert("学的越多,越觉得自己无知!");
  break;
  case "list-2":
  alert("爱是一种艺术!");
  break;
  case "list-3":
  target.innerHTML = "呵呵,我改了啊!";
  break;
  case "list-4":
  target.style.background = "#aaa";
  break;
  case "list-5":
  target.style.color = "red";
  target.style.fontSize = "2em";
  break;
  default:
  break;
 }
 }
},false);

因为事件委托依赖事件冒泡机制,所以,并不是所有的事件都可以进行事件委托。

最适合采用事件委托的事件包括:click、mousedown、mouseup、keydown、keyup 和 keypress。

事件委托只是一种非常不错的事件绑定的思想,所以不应该拘泥于上面的例子,要活学活用! ^_^

移除事件处理程序

我们前面说过,事件处理程序存在于内存中,每当将事件处理程序指定给元素时,运行中的浏览器代码与支持页面交互的 JavaScript 代码之间就会建立一个连接。这种连接越多,页面执行就越慢。前面所说的事件委托就是用来限制建立的连接数量。

还有,就是内存中那些使用完后不再使用的事件处理程序,如果不释放掉,也会影响 Web 应用程序的内存和性能。

<button id="button">提交</button>
var button = document.getElementById("button");
button.onclick = function(){
 // 提交某个表单的操作代码
 button.onclick = null; // 移除事件处理程序
 event.target.firstChild.nodeValue = "提交中。。。";
};

总的原则就是:移除掉那些过时不再使用的事件处理程序,释放内存!

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
SlideView 图片滑动(扩展/收缩)展示效果
Aug 01 Javascript
JQuery解析HTML、JSON和XML实例详解
Mar 29 Javascript
javascript字符串与数组转换汇总
May 26 Javascript
jquery实现Slide Out Navigation滑出式菜单效果代码
Sep 07 Javascript
向JavaScript的数组中添加元素的方法小结
Oct 24 Javascript
JS控制按钮10秒钟后可用的方法
Dec 22 Javascript
基于javascript实现动态时钟效果
Aug 18 Javascript
谈谈JavaScript数组常用方法总结
Jan 24 Javascript
Vue组件模板形式实现对象数组数据循环为树形结构(实例代码)
Jul 31 Javascript
vue translate peoject实现在线翻译功能【新手必看】
Jun 07 Javascript
详解React 服务端渲染方案完美的解决方案
Dec 14 Javascript
在Vue中创建可重用的 Transition的方法
Jun 02 Javascript
Angular指令封装jQuery日期时间插件datetimepicker实现双向绑定示例
Jan 22 #Javascript
Bootstrap 下拉多选框插件Bootstrap Multiselect
Jan 22 #Javascript
JavaScript 详解预编译原理
Jan 22 #Javascript
JavaScript中匿名函数的递归调用
Jan 22 #Javascript
Javascript中字符串和数字的操作方法整理
Jan 22 #Javascript
loading动画特效小结
Jan 22 #Javascript
全面总结Javascript对数组对象的各种操作
Jan 22 #Javascript
You might like
PHP+MYSQL开发工具及资源收藏
2007/01/02 PHP
PHP mail 通过Windows的SMTP发送邮件失败的解决方案
2009/05/27 PHP
php 获取可变函数参数的函数
2009/08/26 PHP
PHP Stream_*系列函数
2010/08/01 PHP
试用php中oci8扩展
2015/06/18 PHP
php构造函数与析构函数
2016/04/23 PHP
jquery 插件开发方法小结
2009/10/23 Javascript
JavaScript 全角转半角部分
2009/10/28 Javascript
javascript代码编写需要注意的7个小细节小结
2011/09/21 Javascript
JQuery 中几个类选择器的简单使用介绍
2013/03/14 Javascript
jQuery Mobile框架中的表单组件基础使用教程
2016/05/17 Javascript
利用vue.js插入dom节点的方法
2017/03/15 Javascript
兼容浏览器的js事件绑定函数(详解)
2017/05/09 Javascript
在 Node.js 中使用原生 ES 模块方法解析
2017/09/19 Javascript
简述JS控制台的使用
2018/07/15 Javascript
element-ui中select组件绑定值改变,触发change事件方法
2018/08/24 Javascript
Node.JS枚举统计当前文件夹和子目录下所有代码文件行数
2019/08/23 Javascript
jQuery模仿ToDoList实现简单的待办事项列表
2019/12/30 jQuery
解决Echarts 显示隐藏后宽度高度变小的问题
2020/07/19 Javascript
如何在vue-cli中使用css-loader实现css module
2021/01/07 Vue.js
[02:30]联想杯DOTA2完美世界全国高校联赛—北京站现场
2015/11/16 DOTA
python学习之matplotlib绘制散点图实例
2017/12/09 Python
python中pygame安装过程(超级详细)
2019/08/04 Python
python使用pymongo与MongoDB基本交互操作示例
2020/04/09 Python
Python接口开发实现步骤详解
2020/04/26 Python
Python 如何调试程序崩溃错误
2020/08/03 Python
Shoes For Crews法国官网:美国领先的防滑鞋设计和制造商
2018/01/01 全球购物
别名指示符是什么
2012/10/08 面试题
一个J2EE项目团队的主要人员组成是什么
2012/06/04 面试题
积极贯彻学习两会精神总结
2014/03/17 职场文书
《春到梅花山》教学反思
2014/04/16 职场文书
信电学院毕业生自荐书
2014/05/24 职场文书
缓刑人员思想汇报
2014/10/11 职场文书
小学班主任工作随笔
2015/08/15 职场文书
nginx如何将http访问的网站改成https访问
2021/03/31 Servers
解决Django transaction进行事务管理踩过的坑
2021/04/24 Python