高性能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 ...
随机推荐
- SQL UCASE() 函数
UCASE() 函数 UCASE 函数把字段的值转换为大写. SQL UCASE() 语法 SELECT UCASE(column_name) FROM table_name SQL UCASE() ...
- iOS开发基础篇-手写控件
一.手写控件的步骤 1)使用相应的控件类创建控件对象: 2)设置该控件的各种属性: 3)添加空间到视图中: 4)如果是 UIButton 等控件,还需考虑控件的单击事件等: 二.添加 UIButton ...
- vue 图片懒加载 vue-lazyload
图片懒加载 在实际的项目开发中,我们通常会遇见这样的场景:一个页面有很多图片,而首屏出现的图片大概就一两张,那么我们还要一次性把所有图片都加载出来吗?显然这是愚蠢的,不仅影响页面渲染速度,还浪费带宽. ...
- python 判断网络通断同时检测网络的状态
思路:通过http判断网络通断,通过ping获取网络的状态 注意:不同平台下,调用的系统命令返回格式可能不同,跨平台使用的时候,注意调整字符串截取的值 主程序:network_testing_v0.3 ...
- Linux中什么是动态网站环境及如何部署
当谈论起网站时,我们可能听说过静态和动态这两个词,但却不知道它们的含义,或者从字面意思了解一些却不知道它们的区别. 这一切可以追溯到网站和网络应用程序,Web应用程序是一个网站,但很多网站不是Web应 ...
- 开发中的Date处理
数据库中的日期格式有以下几种: date:年-月-日 time:时:分:秒 datatime:年-月-日 时:分:秒 timestrap: 例如,生日显示格式为'年-月-日',而创建/更新时间格式为' ...
- XP_CMDSHELL 执行命令添加 windows 用户的方法
1. 之前看过不少文档 可以使用 xp_SQLCMD的命令来进行渗透处理, 今天因为公司的服务器又中毒了 自己学习了下. 2. 修改SQLSERVER的设置 远程登录数据库 sqlcmd -S 10. ...
- VMware Workstation 10序列号:
VMware Workstation 10序列号:1Y0LW-4WJ9N-LZ5G9-Z81QP-92PN7
- [BZOJ 2480] [SPOJ 3105] Mod
Description 已知数 \(a,p,b\),求满足 \(a^x\equiv b\pmod p\) 的最小自然数 \(x\). Input 每个测试文件中最多包含 \(100\) 组测试数据. ...
- 20165223 《信息安全系统设计基础》 实现mybash
一.了解 mybash 1. 简介 bash 是 Bourne Again Shell 的缩写,是linux默认的标准shell(也是大家常说的系统内核),bash也是Unix/Linux上常见的 ...