这段时间把《高性能JavaScript》书籍读完,受益良多。在读书的过程把重点精简地提炼并结合本身的经验记录下来。也但愿看完这篇文章可以给对JavaScript多了解一点点。javascript
了解: 当浏览器在执行JavaScript代码时,是不可以同时作其余事情。由于,绝大多数的浏览器使用单一线程来处理UI和JS。简单地说,< script >标签(内嵌或外链)的出现,页面都会听下来等待脚本下载并执行完成,由于脚本中可能会有修改页面内容的操做。html
<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文件的下载执行流程:: 正则表达式
考虑到Http请求会有额外的开销,因此script标签的个数不能过多。这个时候就要考虑将js文件进行合并已减小数量了。不过如今的不少打包工具都有这样的功能,因此不用太过关注这个问题。算法
减小JS文件的大小及数量是优化的第一步(毕竟效果有限,由于js总会愈来愈多,愈来愈大)因此要考虑无阻塞的加载脚本方式。 而==无阻塞脚本的秘诀在于:页面加载完成后再就在JS代码(即在window.load()方法出发后再下载)==chrome
Defer属性: HTML4为< script >标签订义了defer扩展属性,该属性指明的JS文件不会修改DOM。但一开始只有IE四、FireFox3.5+支持;不事后来已经被全部的主流浏览器所支持。后来的H5中还添加了async扩展属性。 区别编程
defer | async |
---|---|
并行下载JS | 并行下载JS |
等待页面完成后执行(可是在load()方法调用以前) | 下载完成后执行 |
< script >标签跟其余的元素同样,都能经过DOM操做。跨域
let scriptaEle = document.createElement('script');
scriptEle.type = 'text/script';
scriptEle.src = 'file1.js';
document.getElementByTagName('head')[0].appendChild(scriptEle);
复制代码
==这个技术的重点在于:不管什么时候启动下载,文件的下载和执行的过程不会阻塞页面的其余过程。==数组
舒适提示:浏览器
有时该JS会被其余的JS调用其中的方法,因此有时须要监听JS下载的状态。
全部状态 | Value |
---|---|
uninitialized | 初始 |
loading | 开始下载 |
loaded | 下载完成 |
interactive | 完成但未可用 |
complete | 已准备就绪 |
==动态脚本凭借其在跨浏览其兼容性和易用的优点,成为最通用的无阻加载解决方案== 记住哈,想要优化JS的下载就采用动态脚本技术!!!
**了解:**另外一种无阻塞加载脚本方式:使用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代码
有一些如LazyLoad的类库能够协助咱们快速的使用无阻塞加载JS
了解: 计算机科学中有一个经典的问题:经过改变数据的存取位置来得到最佳的读写性能。数据的存取位置关系到代码执行过程当中的检索速度。
js中有四种基本的数据存取位置: 字面量 : 字面量只表明自己,不存储在特定位置。 : 有:字符串、数字、布尔、数组、函数、正则表达式、nullull、undefined 本地变量 : 开发人员使用var、let等定义的数据存储单元 数组元素 : 存储在JS数组对象内部,以数字为索引 对象成员 : 存储在JS对象内部,以字符串为索引
**了解:**做用域是理解JS的关键,因此要重点的搞明白这一部分,从性能和功能的角度去思考。
须要了解以上问题的原理!
**了解:**JS函数是Function对象,和普通对象同样拥有
可编程访问的属性
不可经过代码访问的内部属性(而这其中有着很是重要的 ==[scope]== )
一个标志符所在的位置越深,他的读写速度越慢;因此全局变量访问速度越慢(由于他老是在做用域链的末端) (这也是链式结构的特色) 综上述:应该尽可能多的访问局部变量。 经验法则:若是某个跨做用域的值在函数中被引用一次以上,则把他存储到局部变量
有两个语句能够在执行时,临时改变做用域链。
第一个:with
· 第二个:try...catch
当进入catch时,会将异常对象推入做用域链的顶部
with、try...catch、eval()都被认为是动态做用域链,动态做用域只存在于代码执行过程当中,所以没法经过静态分析。
闭包:js最强的特性之一,函数访问局部做用域以外的数据,使用闭包可能会致使性能问题,由于闭包函数阻碍了函数被正常回收,由于闭包有本身的做用域链,而且指向跟函数的做用域链同样。 当闭包代码执行时,会建立一个执行环境。
访问成员比访问字面量或变量要慢,为了理解其中的缘由,有必要先了解JS的对象本质。
js的对象基于原型,他定义并实现了一个新建立的对象,所必须包含的成员列表。 对象经过一个内部属性帮到他的原型,在firefox、safari、chrome浏览器中,这个属性_proto_对开发者可见,而其余浏览器确不容许脚本访问此属性。
不知不觉写到这里已经挺长的了,因此决定留到下一篇文章吧。 若是以为对你有帮助,就点个喜欢吧!
==支持一下,无限的动力^_^==