第九章 构建并部署高性能JavaScript应用
1 合并多个JS文件,减少HTTP请求数
2 预处理JS文件,虽不会提高性能,但允许你做其他事情,如有条件的插入测试代码来衡 量应用程序的性能
3 压缩JS和CSS
4 只要是能在构建时完成的工作就不要留到运行时去做,如合并、压缩、预处理等
5 JS的压缩有很多工具,如gzip (适合纯文本,有图片不行)、YUI Compressor和Packer,最佳实践是使用YUI Compressor合并再使用gzip压缩,Packer可用于网速较慢或不支持Gzip的情况
6 缓存JS文件。服务器可通过“Expire HTTP响应头”来告诉客户端一个资源应当缓存多长时间,可通过设置缓存时间为一年将缓存时间设为永不过期,然而有的浏览器可能会有缓存限制,此时可考虑采用客户端存储机制,如cookies,localstorage及sessionstorage,不过此时JS代码必须自行控制到期时间,另外还可以使用HTML5离线应用缓存技术,缺点是要确保用户下载的都是最新的内容
7 使用内容分发网络CDN,可增强WEB应用的可靠性,可扩展性还能提高性能。通过向地理位置最近的用户传输内容,CDN能极大减少网络延时
第八章 编程实践
1 避免双重求值。JS允许你在程序中提取一个包含代码的字符串,然后动态执行它。有四种标准方法可以实现:eval,Function()构造函数,setTimeout()和setInterval(),每个方法都允许你传入一个JS代码字符串并执行它,代码字符串指传入的是字符串,但执行时用的是该字符串所对应的值。这些方法都会导致双重求值,因为每次调用这些函数时都要创建一个新的解释器/编译器实例,从而导致代码执行速度变慢。故没必要使用eval()和Function时就避免使用他们。至于setTimeout()和setInterval(),建议传入函数而不是字符串来作为第一个参数
2 使用Object/Array直接量
Var Myobject=new Object();
Myobject.name="nick";
Var Myobject={
name:"nick"
}
推荐使用第二种方式:1 速度快 2 省空间
3 不做重复工作
1 延迟加载(在每个分支语句里覆盖函数即可实现)
2 条件预加载(在脚本加载时就检测,而不是加载后)
4 使用速度快的部分
1 进行数学运算时使用位运算或使用Math对象的API
2 尽量使用原生JS方法,如DOM操作查找节点时可用querySelecto r()方法
第七章 AJAX
1 数据传输--请求数据技术
A .XHR
当使用get方式时,请求的资源会被缓存,只有当url加上参数的长度接近或超过2048个字符时才应该用post。不能跨域请求数据
B. 动态脚本注入
可跨域请求数据,只需用JS动态创建一个脚本标签,然后设置他的src属性为不同域的URL即可,不能设置请求的头信息,只能使用get方式,也不能访问请求的头信息,不能把响应消息作为字符串处理。响应消息是作为脚本标签的源码,故必须是可执行的JS代码,不能使用纯XML,纯Json或其他任何格式的数据,无论哪种格式,都必须封装在一个回调函数中。
C .MXHR
该技术允许客户端只用一个HTTP请求就可以从服务器想客户端传送多个资源。他通过在服务器端将资源打包成一个双方约定的字符串分割的长字符串并发送到客户端,然后用JS代码处理这个长字符串,并根据mime-type类型和传入的其他头信息解析出每个资源。该技术最大的缺点是不能缓存数据
2 数据传输--发送数据技术
A .XHR
B. Beacons(图片信标)
类似于动态脚本注入,使用JS创建一个新的Image对象,并把src属性设置为服务器上脚本的URL,注意没有创建img元素或把他插入DOM,服务器端无需向客户端返回回馈信息,这是给服务器回传信息的最有效的方式。缺点:不能使用post,接收到的响应类型是有限的。适用于只关心发送数据到服务器,不关心返回数据
3 数据格式
A XML
Xpath
B JSON
XHR+JSON,JSON数据被当成字符串返回,然后使用eval()转换为原生对象
动态脚本注入+JSON-P,JSON数据被当成JS文件并作为原生代码执行
C HTML
D 自定义格式
速度最快的是使用数组形式的JSON-P
4 AJAX性能指南之缓存数据
1 设置HTTP头信息
若希望AJAX响应被浏览器缓存,那么必须使用get方式发出请求,并在服务器端设置HTTP头信息中的expire时间
2 本地数据存储
除了依赖浏览器处理缓存外,还可以使用手工方式实现,即直接把服务器接收到的数据储存起来,把响应文本保存到一个对象中,以URL为键值作为索引
var localCathe={};
function xhrRequest(url,callback){
//检查此URL的本地缓存
if(localCathe[url]){
callback.success(localCathe[url]);
return;
}
//此URL缓存不存在
var req=creatXhrObject();
req.onerror=function(){
callback.error();
};
req.onreadystatechange=function(){
if(req.readyState==4){
if(req.responseText===''||req.status=='404'){
callback.error();
return;
}
//存储相应文本到本地缓存
localCathe[url]=req.responseText;
callback.success(req.responseText);
}
};
req.open("GET",url,true);
req.send(null);
}
第五章 字符串与正则表达式
1 字符串连接
str+=s1+s2与str=str+s1+s2的区别:
前者经历四个步骤:1 在内存中创建一个临时字符串2连接s1和s2后赋给该变量3临时字 符串与str连接4 结果赋给str
后者经历两个步骤:1将s1拷贝到str末尾 2将s2拷贝到str+s1的末尾
后者避免了使用临时变量,性能会有提升
2 数组项连接
Array.prototype.join方法将数组的所有元素合并成一个字符串
String.prototype.concat方法通常比+,+=操作符慢
第四章 算法与流程控制
1 JS中共有四种循环,for while do-while for-in,其中for-in用于遍历对象中的属性,
2 改善循环性能的最佳方式是减少每次迭代的运算量(最小化属性查找和倒叙循环法)和减 少循环迭代次数(达夫设备法)
3 通常,switch总是比if-else快,但并不总是最佳解决方案
4 判断条件较多时,使用查找表比if-else和switch更快
5 浏览器调用栈大小限制了递归算法在JS中的应用,栈溢出错误会导致其他代码中断执行, 若遇到这种情况,可将方法改为迭代算法或使用Memoization(使用缓存技术)来避免重 复计算
第三章 DOM编程
1 减少访问DOM的次数,把运算尽量留在ECMAScript这边
2 关于修改页面区域的最佳方案:对于旧版本的浏览器,建议使用innerHTML;对于新版本的浏览器,建议使用DOM方法(creatElement等方法)
3 使用DOM方法更新页面内容的另一个途径是克隆已有元素,而不是创建新元素,即使用cloneNode方法代替creatElement方法,在大多数浏览器中,克隆更有效率
4 HTML集合是包含了DOM节点引用的类数组对象,返回该集合的方法有:getElementsByName() getElementsByClassName() getElementsByTagName() 返回该集合的属性有:document.images document.links document.forms document.forms[0].elements
类数组对象没有push和slice等数组方法,但可以通过下标访问列表中的元素,也提供了length属性,但HTML集合处于一种实时状态,即当底层文档对象更新时他也会自动更新。
Array.prototype.slice.call(HTML集合)可将集合转化为JS数组
5 DOM遍历 1 当你需要从某一个DOM元素开始操作周围的元素或递归查找所有子节点,你可以使用childNodes或nextSibling,在IE中nextSilbing比childNodes快,其他浏览器中差不多 2 使用children代替childNodes 3 使用querySelector和querySelectorAll代替getElementById等方法,用之前要检查浏览器是否支持这两个函数
6 重绘与重排
浏览器下载完页面中的所有组件---HTML标记、JS、CSS、图片之后会解析并生成两个内部数据结构:DOM树和渲染树。当DOM的变化影响了元素的集合属性(宽和高),会引发重排操作,完成重排后再进行重绘操作。重排和重绘都是代价昂贵的操作,应当避免。下列情况会导致重排:(当滚动条出现时会导致整个页面的重排)
1 添加或者删除可见的DOM元素
2 元素位置改变
3 元素尺寸改变
4 元素内容改变(例如:一个文本被另一个不同尺寸的图片替代)
5 页面渲染初始化(这个无法避免)
6 浏览器窗口尺寸改变
注意:1 尽量不要在布局信息改变时做查询,这会导致强制刷新队列并要求计划任务立刻执 行(多数浏览器通过队列化修改并批量执行来优化重排过程)
1 offsetTop, offsetLeft, offsetWidth, offsetHeight
2 scrollTop, scrollLeft, scrollWidth, scrollHeight
3 clientTop, clientLeft, clientWidth, clientHeight
4 getComputedStyle() (currentStyle in IE)
[图片上传失败...(image-e70534-1519915919725)]
2 最小化重排和重绘(将多个操作合并为一个,从而只会修改DOM一次,如cssText 属性)
3 批量修改DOM:1 是元素脱离文档流2对其应用多重改变3把元素带回文档中
让元素脱离文档流的方法:1隐藏元素2使用文档片段(在当前DOM之外构建一 个子树,在拷贝回文档)3 将原始元素拷贝到一个脱离文档的节点中,修改副本再 替换
4 动画中使用绝对定位,使用拖放代理,使用事件委托减少事件处理器的数量
第二章 数据访问
1 JS中有四种基本的数据存取位置:直接量(如字符串,数字,布尔,对象等),变量(用var定义),数组元素,对象成员,一般前两者速度快于后两者
2 通常来说,可以通过把常用的对象成员、数组元素、跨域变量保存在局部变量中来改善JS性能,因为局部变量访问速度最快(缓存全局变量)
3 对象的方法不要赋值给局部变量,把一个方法保存在局部变量会导致this绑定到window
第一章 加载与执行
1 JS代码应该放在</body>标签之前
2 减少<script>标签(每下载一个js文件都会执行,从而导致延时。可通过合并JS文件达到)
3 不要把内嵌脚本紧跟在<link>标签之后(会导致页面阻塞去等待样式表下载)
4 无阻塞脚本技术:1 使用defer属性,只有IE4+和Firefox3.5+支持。带有defer属性的script 元素在DOM加载之前不会执行,而是在onload事件处理器执行之前被调用
2 动态脚本元素
function loadScript (url,callback) {
var script=document.createElement("script");
script.type="text/javascript";
if (script.readyState) {//针对IE
script.onreadystatechange=function () {
if (script.readyState=="loaded"||script.readyState=="complete") {
script.onreadystatechange=null;
callback();
}
};
}else{//针对其他浏览器
script.onload=function(){
callback();
};
}
script.src=url;
document.getElementsByTagName("head")[0].appendChild(script);
}
3 XMLHttpRequest脚本注入
var xhr=new XMLHttpRequest();
xhr.open("get",file1.js,true);
xhr.onreadystatechange=function(){
if(xhr.readyState==4){
if(xhr.status>=200&&xhr.status<300||xhr.status==304){
var script=document.creatElement("script");
script.type="text/javascript";
script.text=xhr.responseText;
document.body.appendChild(script);
}
}
};
xhr.send(null);
优点:下载后不会自动执行;适用于所有主流浏览器
缺点:请求的JS文件必须与所请求的页面同域,即不能从CDN下载
网友评论