高性能JS(读书札记)
第一章:加载和执行
1.1脚本位置
将js脚本放在body底部
1.2组织脚本
文件合并,减少http请求(打包工具)
1.3无阻塞的脚本
js倾向于阻止浏览器的某些处理过程,如http请求和用户界面更新,这是所有开发者面临的最显著的性能问题。
尽管下载单个较大的js文件只产生一次http请求,却会死锁浏览器一大段时间。为避免这种情况,你需要向页面中逐步加载js文件,这样做在某种程度上来说不会阻塞浏览器。
无阻塞脚本的秘诀在于,在页面加载完成后才加载js代码。用专业术语来说,这意味着在window对象的load事件触发后再下载脚本。有很多方式可以做到这一点。
1.3.1延迟的脚本
HTML4为<script>标签添加了defer属性(部分浏览器支持),该属性指明本元素所含脚本不会修改DOM,因此代码能够安全地延迟执行。
1.3.2动态脚本元素
动态加载js文件,无论在何时启动下载,文件的下载和执行过程不会阻塞页面其他进程。
使用动态脚本节点下载文件时,返回的代码通常会立即执行。当脚本“自执行”时,这种机制运行正常。但是当代码只包含供页面其他脚本调用的接口时,你必须跟踪并确保脚本下载完成并准备就绪。可以通过侦听此事件来获得脚本加载完成时的状态:
function loadScript(url ,callback){
var script = documment.creatElement("script")
script.type = "text/javascript";
if(script.readystatechange = function(){//IE
script.onreadystatechange = function(){
if(script.readystate == "load' || script.readystate == "complete"){
script.onraedystatechange = null;
callback();
}
};
}else{//其它浏览器
script.onload = function(){
callback();
};
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}
如果需要动态加载多个js文件,则需确保文件加载的顺序。在所有的主流浏览器中,只有firefox和opera能够按照开发人员指定的顺序执行,其他浏览器会按照从服务端还回的顺序下载和执行代码。你可以将下载操作串联起来以确保下载顺序,如
loadScript("file1.js",function(){
loadScript("file2.js,function(){
loadScript("file3.js,function(){
loadScript("file4.js,function(){
alert("All files are loaded!")
});
});
});
});
尽管方案可行,但如果需要下载的文件较多,这个方案会带来管理上的麻烦。
如果多个文件下载顺序很重要,更好的做法是把它们按照正确顺序写成一个文件(由于这个过程是异步的,因此大一点的文件不会有影响)。
1.3.3XMLHttpRequest脚本注入
此技术会先创建一个XHR对象,然后用它下载js文件,最后通过动态创建<script>元素将代码注入页面中。
1.3.4推荐的无阻塞模式
先添加动态加载所需的代码,然后加载初始化页面所需的剩下的代码。
第二章 数据访问
js的四种基本数据存取位置
直接量
直接量只代表自身,不存储在特定的位置。有字符串、数字、布尔值、对象、数组、函数、正则表达式以及特殊的null和undefined。
变量
开发人员用关键字var定义的数据储存单元。
数组元素
储存在js数组对象内部,以数字作为索引。
对象成员
储存在js对像内部,以字符串作为索引。
大多数情况下,从一个直接量和一个局部变量中存取数据比访问数组元素和对象成员的代价小些。
2.1管理作用域
2.1.1作用域链和标识符解析
function对象的内部属性[[Scope]]包含了一个函数被创建的作用域中对像的集合,这个集合被称为函数的作用域链。
2.1.2标识符解析的性能
标识符解析是有代价的,事实上没有哪种计算机操作可以不产生性能开销。在运行期上下文的作用域中,一个标识符所在的位置越深,它的读写速度也就越慢。
一个好的经验法则:如果某个跨作用域的值在函数中被引用一次以上,那么就把它存储到局部变量中。
2.1.3改变作用域链
一般来说,一个运行期上下文的作用域链是不会改变的。但是,有两个语句可以在执行时临时改变作用域链——with和catch子句。
with包含了参数指定对象的所有属性,这个对象被推入所用作用域链的头部,这意味这所有局部变量第二个作用域链对象中,因此访问的代价更高。
把一个异常对象推入一个可变对象并置于作用域的头部。一旦catch子句执行完毕,作用域链就会返回到之前的状态。
2.1.4动态作用域
2.1.5闭包、作用域和内存
因为闭包的[[Scope]]属性包含了与运行上下文作用域链相同的对象的引用,因此会有一项副作用。通常来说,函数的活动对象,会随同运行期上下文一同销毁。但引入闭包时,由于引用仍然存在于闭包的[[Scope]]属性中,因此激活对象无法被销毁。这意味着脚本中的闭包与非闭包相比,需要更多的内存开销。在大幸Web应用中,这可能是个问题,尤其在IE浏览器中需要关注。由于IE使用非原生js对象来实现DOM对象,因此闭包会导致内存泄漏。
2.2对象成员
2.2.1原型
js中的对象是基于原型的。原型是其他对象的基础,定义并实现了一个新对象必须包含的成员列表。这一概念完全不同于传统面向对象编程语言中“类”的概念,“类”定义了创建新对象的过程。而原型对象为所有对象实例共享,因此这些实例也共享了原型对象的成员。
对象可以有两种成员类型:实例成员和原型成员。
可以用hasOwnProperty()方法来判断对象是否包含特定的实例成员,用in操作符来确定对象是否包含特定的属性。
2.2.2原型链
对象的原型决定了实例的类型。默认情况下,所有对象都是对象(Object)的实例,并继承了所有基本方法。
2.2.3嵌套成员
2.2.4缓存对象成员值
由于所有类似的性能问题都与对象成员有关,因此应该尽可能避免使用它们。更确切地说,应当小心,只有在必要时使用对象成员。
如:
function hasEitherClass(element,className1,className2){
return element.className == className1 ||
element.className == className2;
}
换成
function hasEitherClass(element,className1,className2){
var currentClassName = element.className;
renturn currentClassName == className1 ||
currentClassName ==className2;
}
js的命名空间是导致频繁访问嵌套属性的起因之一,不要再同一个函数里多次查找同一个对象成员,除非它的值改变了。
第3章 DOM编程
用脚本进行DOM操作的代价很昂贵,它是富Web应用中最常见的性能瓶颈。
三类
1.访问和修改DOM元素
2.修改DOM元素的样式会导致重绘(repaint)和重排(reflow)
3.通过DOM事件处理与用户的交互
3.1浏览器中的DOM
DOM与js是两个相互独立的功能,它们通过接口彼此连接,就会产生消耗。
3.2DOM访问与修改
修改元素会更为昂贵,因为它会导致浏览器重新计算页面的几何变化。
3.2.1innerHTML对比DOM方法
最终选择哪种方式取决于你的用户经常使用的浏览器,以及编码习惯。
3.2.2节点克隆
3.2.3HTML集合
HTML集合是包含了DOM节点引用的类数组对象。
读取一个集合的length比读取普通数组的length要慢很多,因为每次都要重新查询。
高性能JS(读书札记)的更多相关文章
- js读书笔记
js读书笔记 基本类型的基本函数总结 1. Boolean() 数据类型 转换为true的值 转换为false的值 Boolean true false String 任何非空字符串 "&q ...
- 《高性能js》读书笔记
第一章:加载和执行 .浏览器的JavaScript的引擎是编译器层的优化: .当浏览器执行JavaScript代码时,不能同时做其他任何事情(单一进程),意味着 .主流浏览器都允许并行下载JS. .减 ...
- 高性能JavaScript读书笔记
零.组织结构 根据引言,作者将全书划分为四个部分: 一.页面加载js的最佳方式(开发前准备) 二.改善js代码的编程技巧(开发中) 三.构建与部署(发布) 四.发布后性能检测与问题追踪(线上问题优化) ...
- 高性能 js -- 无阻塞加载脚本
参考: <<高性能JavaScript>> Nicbolas C. Zakas 著 javascript代码的下载和执行过程会阻塞浏览器的其他进程, 比如页面的绘制, 遇到&l ...
- d3.js读书笔记-1
d3.js入门 d3入门 D3是一个强大的数据可视化工具,它是基于Javascript库的,用于创建数据可视化图形.在生成可视化图形的过程中,需要以下几步: 把数据加载到浏览器的内存空间: 把数据绑定 ...
- JS读书心得:《JavaScript框架设计》——第12章 异步处理
一.何为异步 执行任务的过程可以被分为发起和执行两个部分. 同步执行模式:任务发起后必须等待直到任务执行完成并返回结果后,才会执行下一个任务. 异步执行模式:任务发起后不等待任务执行完成,而是马上 ...
- 高性能JS笔记3——DOM编程
一.访问与修改DOM DOM和JS 相当于两个岛屿,访问操作的次数越多,要交的过路费越多,对性能产生很大影响. 减少访问DOM的次数,把运算尽量留在JS端操作. 二.innerHTML 对比 DOM ...
- 了不起的Node.js读书笔记
原文摘自我的前端博客,欢迎大家来访问 http://www.hacke2.cn 第二章 Js概览 基于GoogleV8引擎 Object.keys(o) 数组方法:遍历forEach.过滤filter ...
- 高性能JS笔记1——加载执行
一.脚本位置 1.Script标签尽可能放到Body底部,以减少脚本文件下载对整个页面UI渲染的影响. 2.Script标签永远不要紧跟Link标签后面. 二.组织脚本 1.合并多个文件在一个Scri ...
随机推荐
- 《通过C#学Proto.Actor模型》之PID
PID对象是代表Actor对象的进程,是能过Actor.Spawn(props)获取的:它有什么成员呢?既然代理Actor,首先有一个ID,标识自己是谁,Actor在Spawn时可以命名这个ID,否则 ...
- 私有云方案——利用阿里云云解析实现DDNS
各位都是程序员,工作中是不是遇到个类似情况.在家里研究的一些开源代码或写的一些demo或试验代码,在工作中正好需要参考一下,但是在家里的电脑上. 虽然这些都可以用云 ...
- 在物理内存中观察CLR托管内存及GC行为
虽然看了一些书,还网络上的一些博文,不过对CLR托管内存细节依然比较模糊.而且因为工作原因总会有很多质疑,想要亲眼看到内存里二进制数据的变化. 所以借助winhex直接查看内存以证实书上的描述或更进一 ...
- FineUIPro v5.1.0 发布了!
FineUIPro v5.1.0 已发布,这已经是自 2014 年以来的第 31 个版本,4 年来精雕细琢,只为你来! 上个大版本新增了响应式布局,而这个版本主要是BUG修正,此外还增加了树控件的级联 ...
- @Valid注解的使用(转)
原文地址:http://blog.csdn.net/xzmeasy/article/details/76098188 @Valid注解用于校验,所属包为:javax.validation.Valid. ...
- JAVA获取计算机CPU、硬盘、主板、网络等信息
通过使用第三方开源jar包sigar.jar我们可以获得本地的信息 1.下载sigar.jar sigar官方主页 sigar-1.6.4.zip 2.按照主页上的说明解压包后将相应的文件copy到j ...
- 前端获取checkbox复选框的值 通过数组形式传递
html代码: <form role="form" class="select_people"> <div style="displ ...
- H5的段落标签、图片标签、列表标签与链接标签
段落标签 (1)<p>段落标签</p> (2)<nobr>强制不换行标签,会出现滚动条</nobr> (3)<pre>保留原始排版标签< ...
- 用pip下载的python模块怎么在PyCharm中引入报错
在IDE中导入下载的模块,比如:numpy模块 你会发现虽然你安装了numpy模块,在CMD中python可以import numpy,但是你在PyCharm引不进去,为什么呢?你要是有注意的话,安装 ...
- python之pymongo
引入 在这里我们来看一下Python3下MongoDB的存储操作,在本节开始之前请确保你已经安装好了MongoDB并启动了其服务,另外安装好了Python的PyMongo库. MongoDB 数据库安 ...