javascript性能优化

本文主要是在我读《高性能Javascript》之后,想要记录下一些有用的优化方案,并且就我本身的一些经验,来大家一起分享下

Javascript的加载与执行

大家都知道,浏览器在解析DOM树的时候,当解析到script标签的时候,会阻塞其他的所有任务,直到该js文件下载、解析执行完成后,才会继续往下执行。因此,这个时候浏览器就会被阻塞在这里,如果将script标签放在head里的话,那么在该js文件加载执行前,用户只能看到空白的页面,这样的用户体验肯定是特别烂。对此,常用的方法有以下:

  • 将所有的script标签都放到body最底部,这样可以保证js文件是最后加载并执行的,可以先将页面展现给用户。但是,你首先得清楚,页面的首屏渲染是否依赖于你的部分js文件,如果是的话,则需要将这一部分js文件放到head上。
  • 使用defer,比如下面这种写法。使用defer这种写法时,虽然浏览器解析到该标签的时候,也会下载对应的js文件,不过它并不会马上执行,而是会等到DOM解析完后(DomContentLoader之前)才会执行这些js文件。因此,就不会阻塞到浏览器。

<script src="test.js" type="text/javascript" defer></script>
  • 动态加载js文件,通过这种方式,可以在页面加载完成后,再去加载所需要的代码,也可以通过这种方式实现js文件懒加载/按需加载,比如现在比较常见的,就是webpack结合vue-router/react-router实现按需加载,只有访问到具体路由的时候,才加载相应的代码。具体的方法如下:

1.动态的插入script标签来加载脚本,比如通过以下代码

function loadScript(url, callback) {const script = document.createElement('script');script.type = 'text/javascript';// 处理IEif (script.readyState) {script.onreadystatechange = function () {if (script.readyState === 'loaded' || script.readyState === 'complete') {script.onreadystatechange = null;callback();}}} else {// 处理其他浏览器的情况script.onload = function () {callback();}}script.src = url;document.body.append(script);}// 动态加载jsloadScript('file.js', function () {console.log('加载完成');})

2.通过xhr方式加载js文件,不过通过这种方式的话,就可能会面临着跨域的问题。例子如下:

const xhr = new XMLHttpRequest();xhr.open('get', 'file.js');xhr.onreadystatechange = function () {if (xhr.readyState === 4) {if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {const script = document.createElement('script');script.type = 'text/javascript';script.text = xhr.responseText;document.body.append(script);}}}

3.将多个js文件合并为同一个,并且进行压缩。 原因:目前浏览器大多已经支持并行下载js文件了,但是并发下载还是有一定的数量限制了(基于浏览器,一部分浏览器只能下载4个),并且,每一个js文件都需要建立一次额外的http连接,加载4个25KB的文件比起加载一个100KB的文件消耗的时间要大。因此,我们最好就是将多个js文件合并为同一个,并且进行代码压缩。

javascript作用域

当一个函数执行的时候,会生成一个执行上下文,这个执行上下文定义了函数执行时的环境。当函数执行完毕后,这个执行上下文就会被销毁。因此,多次调用同一个函数会导致创建多个执行上下文。每隔执行上下文都有自己的作用域链。相信大家应该早就知道了作用域这个东西,对于一个函数而言,其第一个作用域就是它函数内部的变量。在函数执行过程中,每遇到一个变量,都会搜索函数的作用域链找到第一个匹配的变量,首先查找函数内部的变量,之后再沿着作用域链逐层寻找。因此,若我们要访问最外层的变量(全局变量),则相比直接访问内部的变量而言,会带来比较大的性能损耗。因此,我们可以将经常使用的全局变量引用储存在一个局部变量里


const a = 5;
function outter () {const a = 2;function inner () {const b = 2;console.log(b); // 2console.log(a); // 2}inner();
}

对象的读取

javascript中,主要分为字面量、局部变量、数组元素和对象这四种。访问字面量和局部变量的速度最快,而访问数组元素和对象成员相对较慢。而访问对象成员的时候,就和作用域链一样,是在原型链(prototype)上进行查找。因此,若查找的成员在原型链位置太深,则访问速度越慢。因此,我们应该尽可能的减少对象成员的查找次数和嵌套深度。比如以下代码

// 进行两次对象成员查找function hasEitherClass(element, className1, className2) {return element.className === className1 || element.className === className2;}// 优化,如果该变量不会改变,则可以使用局部变量保存查找的内容function hasEitherClass(element, className1, className2) {const currentClassName = element.className;return currentClassName === className1 || currentClassName === className2;}

DOM操作优化

  • 最小化DOM的操作次数,尽可能的用javascript来处理,并且尽可能的使用局部变量储存DOM节点。比如以下的代码:
// 优化前,在每次循环的时候,都要获取id为t的节点,并且设置它的innerHTMLfunction innerHTMLLoop () {for (let count = 0; count < 15000; count++) {document.getElementById('t').innerHTML += 'a';}}// 优化后,function innerHTMLLoop () {const tNode = document.getElemenById('t');const insertHtml = '';for (let count = 0; count < 15000; count++) {insertHtml += 'a';}tNode.innerHtml += insertHtml;}
  • 尽可能的减少重排和重绘,重排和重汇可能会代价非常昂贵,因此,为了减少重排重汇的发生次数,我们可以做以下的优化

1.当我们要对Dom的样式进行修改的时候,我们应该尽可能的合并所有的修改并且一次处理,减少重排和重汇的次数。

// 优化前const el = document.getElementById('test');el.style.borderLeft = '1px';el.style.borderRight = '2px';el.style.padding = '5px';// 优化后,一次性修改样式,这样可以将三次重排减少到一次重排const el = document.getElementById('test');el.style.cssText += '; border-left: 1px ;border-right: 2px; padding: 5px;'

2.当我们要批量修改DOM节点的时候,我们可以将DOM节点隐藏掉,然后进行一系列的修改操作,之后再将其设置为可见,这样就可以最多只进行两次重排。具体的方法如下:

// 未优化前const ele = document.getElementById('test');// 一系列dom修改操作// 优化方案一,将要修改的节点设置为不显示,之后对它进行修改,修改完成后再显示该节点,从而只需要两次重排const ele = document.getElementById('test');ele.style.display = 'none';// 一系列dom修改操作ele.style.display = 'block';// 优化方案二,首先创建一个文档片段(documentFragment),然后对该片段进行修改,之后将文档片段插入到文档中,只有最后将文档片段插入文档的时候会引起重排,因此只会触发一次重排。。const fragment = document.createDocumentFragment();const ele = document.getElementById('test');// 一系列dom修改操作ele.appendChild(fragment);

3.使用事件委托:事件委托就是将目标节点的事件移到父节点来处理,由于浏览器冒泡的特点,当目标节点触发了该事件的时候,父节点也会触发该事件。因此,由父节点来负责监听和处理该事件。

那么,它的优点在哪里呢?假设你有一个列表,里面每一个列表项都需要绑定相同的事件,而这个列表可能会频繁的插入和删除。如果按照平常的方法,你只能给每一个列表项都绑定一个事件处理器,并且,每当插入新的列表项的时候,你也需要为新的列表项注册新的事件处理器。这样的话,如果列表项很大的话,就会导致有特别多的事件处理器,造成极大的性能问题。而通过事件委托,我们只需要在列表项的父节点监听这个事件,由它来统一处理就可以了。这样,对于新增的列表项也不需要做额外的处理。而且事件委托的用法其实也很简单:


function handleClick(target) {// 点击列表项的处理事件
}
function delegate (e) {// 判断目标对象是否为列表项if (e.target.nodeName === 'LI') {handleClick(e.target);}
}
const parent = document.getElementById('parent');
parent.addEventListener('click', delegate);

本文地址在->本人博客地址, 欢迎给个 start 或 follow

原文地址:https://segmentfault.com/a/1190000017044045

转载于:https://www.cnblogs.com/lalalagq/p/9989069.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/484730.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第一章 计算机系统概述 1.2.2 各硬件部分的介绍 [计算机组成原理笔记]

第一章 计算机系统概述 1.2.2 各硬件部分的介绍 本笔记参考书目: 计算机组成原理(第六版.立体化教材)白中英、戴志涛2021王道计算机组成原理视频公开课 本节重点: 主存储器、运算器和控制器的基本组成计算机运行过程的实例 转…

GAN网络立功!36分钟,建起5亿光年的宇宙区域

来源:simonsfoundation编译:周熙利用神经网络,Flatiron研究所的研究员Yin Li和他的同事只花费了传统方法所需时间千分之一,就成功模拟了庞大而复杂的宇宙。该方法提出者在5月4日在线发表于《美国国家科学院院刊》的一项研究中报告…

STM32F407 开发环境搭建 程序下载 个人笔记

详细资料: http://www.openedv.com/thread-13912-1-1.html 需要安装的软件: 1.keil(MDK,必选),用keygen破解 2.CH340驱动,(usb串口驱动,用来下载程序。方便但下载速度较慢…

第一章 计算机系统概述 1.2.3 计算机的多级层次结构 [计算机组成原理笔记]

第一章 计算机系统概述 1.2.3 计算机的多级层次结构 本笔记参考书目: 计算机组成原理(第六版.立体化教材)白中英、戴志涛2021王道计算机组成原理视频公开课 本节重点: 计算机系统的五层结构:微程序机器、传统机器、…

从多维度解析神经科学中的视觉编码

来源:脑人言一棵树是如何被知觉为“一棵树”?我又是如何认出你是“你”?我们可能会说这很大程度依赖于我们的视觉感知。以后者为例,从你身上反射的光将你的信息传入我眼,当抵达视网膜感受器时,光转换为携带…

linux和windows下忘记mysql密码的几种找回方法

linux和windows下忘记mysql密码的几种找回方法 关于linux忘记mysql密码处理方法,下面提供了5种linux忘记mysql密码找回方法哦。方法一(先进入root权限):# /etc/init.d/mysql stop# mysqld_safe --usermysql --skip-grant-tables --skip-networking &…

突发!美国最大输油管道遭网络攻击关闭!美媒:为其基础设施的脆弱堪忧

来源:雷锋网(leiphone-sz)作者:代润泽“这不仅是一条输油管道,可以说已经接近美国基础设施的大动脉。”你能想象,美国最大的燃油管道运营商能因为网络攻击被迫停运!CNN网站消息,当地…

old boy

https://www.cnblogs.com/alex3714/articles/5885096.html转载于:https://www.cnblogs.com/dhName/p/9999549.html

第一章 计算机系统概述 1.3 计算机的性能指标 [计算机组成原理笔记]

第一章 计算机系统概述 1.3 计算机的性能指标 本笔记参考书目: 计算机组成原理(第六版.立体化教材)白中英、戴志涛2021王道计算机组成原理视频公开课 本节重点: 容量计算K/M/G/T单位转换CPU主频/CPI/IPS/FLOPS数据通路带宽/吞吐…

机器学习漫谈:还有很长的路要走

来源:王宏琳科学网博客链接地址:http://blog.sciencenet.cn/blog-3005681-1285948.html 人工智能已经成为大数据、机器人和物联网等新兴技术的主要驱动力,在可预见的未来,它将继续驱动技术创新,影响着几乎每个行业和每…

第一章 计算机网络 1 计网体系结构的概念和功能 [计算机网络笔记]

第一章 计算机网络 1 计网体系结构的概念和功能 本笔记参考书目: 计算机网络(第8版)谢希仁2021王道计算机网络视频公开课 本节重点: 因特网的三个发展阶段 转载请注明文章来源! ——计算机网络的分层结构是类&…

第一章 计算机网络 2 组成与分类 [计算机网络笔记]

第一章 计算机网络 2 组成与分类 本笔记参考书目: 计算机网络(第8版)谢希仁2021王道计算机网络视频公开课 本节重点: 计网的组成与分类 转载请注明文章来源! 计算机网络的组成 组成部分 : 硬件、软件、…

企业——Docker容器的搭建及简单应用

1.环境需求 不需要开虚拟机,只需要一个真机就行。 下载docker的安装包,可以在官网上下载 www.docker.com yum install -y pigz-2.3.4-1.el7.x86_64.rpm docker-ce-18.03.1.ce-1.el7.centos.x86_64.rpm container-selinux-2.21-1.el7.noarch.rpm   …

第一章 计算机网络 3 标准化工作和相关组织 [计算机网络笔记] -简单浏览了解即可

第一章 计算机网络 3 标准化工作和相关组织 本笔记参考书目: 计算机网络(第8版)谢希仁2021王道计算机网络视频公开课 本节重点: 标准化工作和相关组织 转载请注明文章来源! 标准化分类 标准化流程 标准化相关组织 …

20181123_任务(套件培训)

东西没有做好懒之外还有就是你的way不行!!! 上午: 9:00~11:30:逐日套件深入学习;11:30~14:30:午饭和午休;下午: 15:00~17:00:套件培训;17:30~19:3…

张亚勤、韦乐平等综述论文:通信人工智能的下一个十年

来源:专知【摘 要】移动通信技术走过了37年的发展历程,人工智能技术也已走过了64年的发展历程。从早期的各自独立演进,到5G与人工智能开始深度融合发展,“5G与人工智能”已被业界视为一组最新的通用目的技术组合,对垂…

Juventas, the Roman Goddess of Youth [ Juventas, 罗马青春女神]

Juventas, the Roman Goddess of Youth 👸 Juventas, 罗马青春女神——尤文图斯 Introduction Juventas was a minor Roman goddess whose attributes were regarded by the Romans as applying particularly to the imperishable vigour and immortal glory of t…

python语言中的数据类型之字典

数据类型 字典类型dict 用途:记录多个值,列表是索引对应值,而字典是key对应值,其中key对value有描述性 定义方式:在{ }用逗号分隔开多个元素,每个元素都是key:value形式,其中key是不可变类型&a…

Hinton的GLOM模型与千脑理论有何本质不同?

来源:AI科技评论编译 :琰琰校对 :青暮Geoffrey Hinton在最新发表的一篇论文“如何在神经网络中表示部分-整体层次结构”中提出了一种被称为GLOM的新理论。关于GLOM模型与千脑理论( Thousand Brains Theory )之间有何差…

ThinkPHP3(添加,修改,删除)

实现商品的添加 1、在add.html页面中更改表单元素的名称 Goods控制器的add()方法中获取商品分类 在add.html中循环获取 2、设置提交的位置 3、添加商品代码参见GoodsController.class.php 方法一: $this->redirect();也是跳转 方法二(用cr…