高性能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 ...
随机推荐
- Android图片选择---MultiImageSelector的使用
Github地址:https://github.com/lovetuzitong/MultiImageSelector MultiImageSelector主要是图片选择功能. AndroidStud ...
- log4cplus 简单记录
请注意区别对待: 1.2.1 : 不支持 C++11,比如 std::move 就会 fail. 2.0.1 : 支持 C++11,比如 std::move 就 ok. 完.
- 微信小程序测试
1.连接真机,微信已经登录过了 2.代码: 3.appium自带的识别工具 4.设置工具连接设备的方式 参考资料: https://www.cnblogs.com/yoyoketang/p/91449 ...
- 异步渲染页面怎么点击checkbox获取value值
前后端分离时 后端向前端传递json数据 前端根据需要进行页面渲染 因为是异步渲染 想要获取获取渲染数据里面的值时获取不到的 介绍两个方法: 1,设置全局变量 即渲染时在html页面设置全局变量 如 ...
- yum 彻底删除nodejs,重新安装
第一步 用自带的包管理先删除一次 yum remove nodejs npm -y1手动删除残留 进入 /usr/local/lib 删除所有 node 和 node_modules文件夹进入 /us ...
- NIO原理及案例使用
什么是NIO Java提供了一个叫作NIO(New I/O)的第二个I/O系统,NIO提供了与标准I/O API不同的I/O处理方式.它是Java用来替代传统I/O API(自Java 1.4以来). ...
- EQueue
EQueue 2.3.2版本发布(支持高可用) - dotNET跨平台 - CSDN博客https://blog.csdn.net/sD7O95O/article/details/78097193 E ...
- CLOUD清理临时表空间
--查找空间名.物理空间路径 SELECT name, physical_nameFROM sys.master_filesWHERE database_id = DB_ID('tempdb'); 可 ...
- python+opencv读取视频,调用摄像头
引用 import cv2 import numpy 创建摄像头对象 cap = cv2.VideoCapture("videoTest/test1.mp4") #参数为视频文件目 ...
- ABP项目启动及源代码结构
在整体介绍ABP项目之前我们需要从官方网站下载模板项目,下载以后放到一个本地目录下,启动VS打开源代码.具体下载的步骤如下: 一 创建ABP项目模板 1 进入官方网站然后选择特定的样板项目. 2 ...