写出高性能javascript,必读《一》

前言

这段时间把《高性能JavaScript》书籍读完,受益良多。在读书的过程把重点精简地提炼并结合本身的经验记录下来。也但愿看完这篇文章可以给对JavaScript多了解一点点。javascript

目录

  • 加载和执行
  • 数据存取
  • DOM编程
  • 算法和流程控制
  • 快速响应的用户界面
  • Ajax
  • 编程实战
  • 构建并部署高性能的JavaScript应用

1. 加载和执行

了解: 当浏览器在执行JavaScript代码时,是不可以同时作其余事情。由于,绝大多数的浏览器使用单一线程来处理UI和JS。简单地说,< script >标签(内嵌或外链)的出现,页面都会听下来等待脚本下载并执行完成,由于脚本中可能会有修改页面内容的操做。html

1.1 脚本的位置

<html>
	<head>
		<script 1></script>
		<script 2></script>
		<script 3></script>
	</head>
	<body>
		<div></div>
	</body>
</html>
复制代码

这样的代码存在十分严重的性能问题,整个解析的过程会卡顿在<script 1,2,3>的下载和执行的过程。而页面内容迟迟不能呈如今用户面前。 记住: 浏览器在解析n以前不会渲染页面的任何部分,此时的表现为空白。因此 < script > 放在顶部的作法很是不可取。java

js文件的下载执行流程:: 正则表达式

在这里插入图片描述
==那么该如何去改进?== !!!并行下载js (后来的IE八、FireFox3.五、Safari四、Chrome2都容许并行下载JS文件了,也就是说你如今接触到的大多浏览器的JS文件的下载都是并行的) 也就是:::
在这里插入图片描述
JS文件是可以并行下载,可是页面仍是会阻塞其余资源下载(如图片)而且会等待全部的JS文件下载完成并执行完成。 所以强烈推荐将全部的< script >标签尽量的防盗标签的底部,已尽可能减小对整个页面的影响。

1.2 组织脚本

考虑到Http请求会有额外的开销,因此script标签的个数不能过多。这个时候就要考虑将js文件进行合并已减小数量了。不过如今的不少打包工具都有这样的功能,因此不用太过关注这个问题。算法

1.3无阻塞脚本

减小JS文件的大小及数量是优化的第一步(毕竟效果有限,由于js总会愈来愈多,愈来愈大)因此要考虑无阻塞的加载脚本方式。 而==无阻塞脚本的秘诀在于:页面加载完成后再就在JS代码(即在window.load()方法出发后再下载)==chrome

1.4延迟的脚本

Defer属性: HTML4为< script >标签订义了defer扩展属性,该属性指明的JS文件不会修改DOM。但一开始只有IE四、FireFox3.5+支持;不事后来已经被全部的主流浏览器所支持。后来的H5中还添加了async扩展属性。 区别编程

defer async
并行下载JS 并行下载JS
等待页面完成后执行(可是在load()方法调用以前) 下载完成后执行

1.5动态脚本

< script >标签跟其余的元素同样,都能经过DOM操做。跨域

let scriptaEle = document.createElement('script');
scriptEle.type = 'text/script';
scriptEle.src = 'file1.js';
document.getElementByTagName('head')[0].appendChild(scriptEle);
复制代码

==这个技术的重点在于:不管什么时候启动下载,文件的下载和执行的过程不会阻塞页面的其余过程。==数组

舒适提示:浏览器

  • 新建立的JS添加到< head >中会更好,由于在< body >中IE中可能会抛出“操做已终止”的信息
  • 下载的JS一般会当即执行,除了opera和firefox会等待此前全部的动态脚本节点执行完毕)

有时该JS会被其余的JS调用其中的方法,因此有时须要监听JS下载的状态。

  • firefox、opera、chrome、safari3以上 | 完成时会触发load()函数
  • IE为< script >提供readystate属性,但并非其中的全部状态都会执行(一般loaded/complete出现一种就能够)
全部状态 Value
uninitialized 初始
loading 开始下载
loaded 下载完成
interactive 完成但未可用
complete 已准备就绪

==动态脚本凭借其在跨浏览其兼容性和易用的优点,成为最通用的无阻加载解决方案== 记住哈,想要优化JS的下载就采用动态脚本技术!!!

1.6 XMLHttpRequest脚本注入

**了解:**另外一种无阻塞加载脚本方式:使用XMLHttpRequest技术获取脚本并注入页面(也就是用XHR网络请求JS而后注入到页面中) 例如:

let xhr = new XMLHttpRequest();
xhr.open('get','file.js',true);
xhr.onReadyStateChange = function () {
	if(xhr.readyState === 4) {\
		if(xhr.state >= 200 && xhr.status < 300 || ==304) {
			//请求JS成功后,建立script标签,将JS内容赋给script标签;而后嵌入页面 
			let script = document.createElement('script');
			script.type = 'text/javascript';
			script.text = xhr.responseText;
			document.body.appendChild(script);
		}
	}
}
// 发起请求
xhr.send();
复制代码

优势:

  • JS不会当即执行,能够放到你准备好的时候再执行均可以(灵活控制JS的执行时间)
  • 全部主浏览器都支持

1.7 推荐的无阻塞模式

向页面中添加大量JS的推荐作法: 第一步:先添加动态加载全部的代码 第二部:再加载剩余JS代码

有一些如LazyLoad的类库能够协助咱们快速的使用无阻塞加载JS

2. 数据存取

了解: 计算机科学中有一个经典的问题:经过改变数据的存取位置来得到最佳的读写性能。数据的存取位置关系到代码执行过程当中的检索速度。

js中有四种基本的数据存取位置: 字面量 : 字面量只表明自己,不存储在特定位置。 : 有:字符串、数字、布尔、数组、函数、正则表达式、nullull、undefined 本地变量 : 开发人员使用var、let等定义的数据存储单元 数组元素 : 存储在JS数组对象内部,以数字为索引 对象成员 : 存储在JS对象内部,以字符串为索引

2.1 管理做用域

**了解:**做用域是理解JS的关键,因此要重点的搞明白这一部分,从性能和功能的角度去思考。

  • 肯定哪些变量能被访问
  • 肯定this
  • 关系到性能

须要了解以上问题的原理!

2.2 做用域链和标志符解析

**了解:**JS函数是Function对象,和普通对象同样拥有

  • 可编程访问的属性

  • 不可经过代码访问的内部属性(而这其中有着很是重要的 ==[scope]== )

    在这里插入图片描述
    函数执行时建立一个为执行环境的内部对象。函数每次执行的都会建立独一无二的执行环境。当函数执行完毕,执行环境就会被销毁。 每一个执行环境都有本身的做用域链,用于解析标志符,在函数执行的过程当中,每遇到一个变量,都会经历标志符解析的过程以决定从哪里获取存储数据。从顶层的“活动对象”做用域开始便利做用域链,知道找到为止。 ==正式这个搜索过程,影响性能==

    2.2 标志符解析的性能

    一个标志符所在的位置越深,他的读写速度越慢;因此全局变量访问速度越慢(由于他老是在做用域链的末端) (这也是链式结构的特色) 综上述:应该尽可能多的访问局部变量。 经验法则:若是某个跨做用域的值在函数中被引用一次以上,则把他存储到局部变量

    2.3 改变做用域链

    有两个语句能够在执行时,临时改变做用域链。

    第一个:with

    • 相似功能一般用来避免书写重复代码。
    • 给对象的全部属性建立了一个变量。
    • 而且把该对象添加到做用域链顶,访问该属性速度变快,可是访问其余的变慢
    • 通常来讲若是屡次访问document,能够吧document付给局部变量便可大大提高性能
    • with应该尽可能避免使用

· 第二个:try...catch

  • 当进入catch时,会将异常对象推入做用域链的顶部

    2.4 动态做用域

    with、try...catch、eval()都被认为是动态做用域链,动态做用域只存在于代码执行过程当中,所以没法经过静态分析。

    2.5 闭包、做用域和内存

    闭包:js最强的特性之一,函数访问局部做用域以外的数据,使用闭包可能会致使性能问题,由于闭包函数阻碍了函数被正常回收,由于闭包有本身的做用域链,而且指向跟函数的做用域链同样。 当闭包代码执行时,会建立一个执行环境。

    在这里插入图片描述
    ==闭包代码中访问的属性的位置不在第一层,这就是使用闭包最需关注的性能点==;在频繁访问跨做用域的标志符时,每次都有性能损失。(闭包同时关系到内存和执行速度)

    2.6 对象成员

    访问成员比访问字面量或变量要慢,为了理解其中的缘由,有必要先了解JS的对象本质。

    2.7 原型

    js的对象基于原型,他定义并实现了一个新建立的对象,所必须包含的成员列表。 对象经过一个内部属性帮到他的原型,在firefox、safari、chrome浏览器中,这个属性_proto_对开发者可见,而其余浏览器确不容许脚本访问此属性。

    小结

    • 在JS中,数据存储的位置对代码总体性能产生重大的影响。
    • 访问字面量和局部变量速度最快,相反,访问数组元素和对象成员相对较慢
    • 因为局部变量在链顶位置,因此更快
    • 全局变量在链尾位置,因此更慢
    • 减小嵌套对象
    • 一般来讲,把经常使用的对象成员,数组元素,跨域变量保存到局部变量中可改变JS的性能
    • 多用局部变量

不知不觉写到这里已经挺长的了,因此决定留到下一篇文章吧。 若是以为对你有帮助,就点个喜欢吧!

==支持一下,无限的动力^_^==

  • 加载和执行
  • 数据存取
  • DOM编程
  • 算法和流程控制
  • 快速响应的用户界面
  • Ajax
  • 编程实战
  • 构建并部署高性能的JavaScript应用
相关文章
相关标签/搜索