一: 加载和执行
1.<script> 标签放在页面底部,</body > 闭合标签之前, 这能确保在脚本执行前页面已经完成渲染
2. 合并脚本页面中 < script > 标签越少加载越快
3. 无阻塞下载脚本: defer(延迟加载)async(异步加载)动态创建 < script > 元素下载并执行使用 XHR 对象下载 js 代码并注入页面中
二数据存取
四种基本数据存储方式: 字面量 (基本类型: 字符串数字布尔值对象数组函数正则式, 直接赋值不用 new 的等式右边的值) 变量数组项对象成员
1. 访问字面量和局部变量最快, 访问数组和对象成员相对较慢
2. 局部变量在作用域链的起始位置, 因此访问局部变量比访问跨作用域变量更快
3. 避免使用 with 语句, 它会改变执行环境作用域链, 变量深度有变
4. 嵌套的对象成员少用, 会明显影响性能执行 location.href 比 Window.location.href 快
5. 属性或方法在原型链中的位置越深, 访问它速度越慢
通常来说, 可以把常用的对象成员数组元素跨域变量保存在局部变量中来改善 js 性能, 因为局部变量访问速度更快
对象字面量比 new Object()更高效:{}字面量可立即求值, 而 new Object()本质上是方法调用, 所以需要作用域解析, 找到同名函数后创建对象
对象字面量 vs 构造函数创建对象对比(字面量优势):
a. 它的代码量更少, 更易读;
b. 它可以强调对象就是一个简单的可变的散列表, 而不必一定派生自某个类;
c. 对象字面量运行速度更快, 因为它们可以在解析的时候被优化: 它们不需要 "作用域解析 (scope resolution)"; 因为存在我们创建了一个同名的构造函数 Object() 的可能, 当我们调用 Object()的时候, 解析器需要顺着作用域链从当前作用域开始查找, 如果在当前作用域找到了名为 Object()的函数就执行, 如果没找到, 就继续顺着作用域链往上找, 直到找到全局 Object()构造函数为止
d.Object()构造函数可以接收参数, 通过这个参数可以把对象实例的创建过程委托给另一个内置构造函数, 并返回另外一个对象实例, 而这往往不是你想要的
- // 对象直接量定义
- var o = {
- propertyfun: function ([parameters]) {},
- get property() {},
- set property(value) {},
- };
通过对象字面量和构造函数创建对象的区别: https://segmentfault.com/a/1190000008462406
三: DOM 操作
1. 最小化 DOM 访问次数, 尽可能在 JS 端处理 (DOM 渲染引擎和 js 引擎是独立的, 交互消耗性能) 如遍历. innerhtml+=a 赋值时, 可先把 aa.. 内容合并然后一次性赋值
2. 如果需要多次访问某个 DOM 节点, 使用局部变量存储它的引用
3. 小心处理 HTML 集合(如 document.images,document.links 返回 a 元素), 因为它实时联系着底层文档如果需要遍历时, 集合长度缓存到变量, 如果需要经常操作集合, 可以复制到一个数组中 DOM 标准中 HTML 集合以一种假定实时态实时存在, 当底层文档对象更新时, 它也会自动更新, 即使获取集合元素个数也会执行询问过程
4. 如果可能的话, 使用速度更快的 API, 如 queryselectorall(返回 NodeList , 返回的不是 HTML 集合, 因此返回的节点不会对应实时的文档结构而 document.getElementById()是 HTML 集合, 需要把它拷贝到数组中才能得到类似 qall 类似的静态列表)和 firstElementChild
5. 注意重绘 (非几何属性变化后引起) 和重排(几何属性和页面布局改变时重排优化: 通过队列化修改并批量执行来优化重排过程, 但部分方法会强制刷新渲染队列, 如 offsetTop 偏移量 / scrollLeft 滚动位置 / clientWidth 系列和计算出样式值 getComputedStyle/currentStyle): 最小化重排和重绘合并多次对 DOM 和样式的修改; 批量修改样式时, 离线操作 Dom 树(脱离文档: display, 文档片段, 复制节点), 使用缓存布局信息(偏移量等), 并减少访问局部信息的次数
6. 动画中使用绝对定位(减少刷新渲染队列), 使用拖放代理()
7. 使用事件委托 (target/scrElement) 来减少事件处理器的数量
四: 算法和流程控制
1. 在判断条件较多时, 使用查找表比 if-else 和 switch 更快
2. 浏览器调用栈大小限制了递归算法在 js 中的应用, 栈溢出会导致代码中断可改为迭代算法或 Memoization(缓存运算结果的方法)来避免重复计算
五: 字符串和正则表达式
1. 不考虑 IE7 数组项合并是比较慢的字符串连接方法, 可用简单的 + 和 += 操作符替代, 避免不必要的中间字符串(IE 除外, 其他浏览器器会尝试为表达式左侧的字符串分配更多的内存, 然后简单将第二个字符串拷贝到它的末尾如果循环中基础字符串位于最左端, 可以避免重复拷贝一个逐渐变大的基础字符串例: str +=one;str +=two 可使用 str=str+one+two 提升性能, str 作为基础, 每次给它附加一个字符串. 但如果 str =one+str+two 优化失效)
2. 正则式处理好回溯问题
六: 快速响应的用户界面
1. 任何 js 任务都不应当执行超过 100 毫秒过长运行时间导致 UI 更新出现明显迟缓影响用户体验
2. 可使用定时器分解大任务为小任务后执行, 或使用 webWorker, 它允许在 UI 线程外执行 js 代码, 从而避免锁定 UI
七: 快速响应的用户界面
1. 选择正确的数据格式: 纯文本和 html 只适用于特定场合, 可节省客户端 CPU 周期; XML 支持良好但它十分笨重且解析缓慢; JSON 轻量级, 解析速度快; 字符分隔自定义格式十分轻量级, 在解析大量数据集时非常快, 但需要编写额外的服务端构造程序, 并在客户端解析
2. 数据请求方式
XMLHttpRequest(XHR): 不能从外域请求数据, 从服务器端返回的数据被当做字符串或 XML, 这意味着处理大量数据将会很慢不改变服务器状态, 只获取数据的请求使用 get, 使用 Get 请求的数据会被缓存起来参数超过 2048 个字符可使用 POST 请求
Dynamic script tag insertion 动态脚本注入: 可跨域请求 var el=document.createElement(script);el.src=;(head)[0].appendChild(el);
缺点: 不能设置请求头, 只能用 get 方式, 不能设置请求超时处理或重试, 是否失败也不一定知道响应消息作为脚本标签的源码, 它必须是可执行的 js 代码
- Iframes
- Comet:
Beacons: 类似动态脚本注入, 使用 js 创建 Image 对象, 把 src 设置为服务器上的脚本 url 适合发送少量数据返回信息不太重要
- var beacon= new Image();
- beacon.src=url+?key1=value1;
- beacon.onload=function(){ if(this.width==1){
- // 如约定返回图片宽度为 1 表示成功 2 表示重试, 如果无需返回数据返回一个 204 no content 它将阻止客户端继续等待永远不会到来的消息正文
- }else if(this.width==2){
- //2 否则重试
- }}
- beacon.onerror=function(){}
Multipart XHR: 允许客户端只用一个 http 请求就可以从服务端向客户端传送多个资源数据不能缓存
注: 任何数据类型都可以被 js 作为字符串发送
3. 减少请求数, 可通过合并 jsCSS 文件或使用 MXHR;
4. 缩短页面加载时间, 页面主要内容加载完成后, 用 ajax 获取次要文件
八: 编程实践
1. 避免使用 eval 和 Funciton 构造器来避免双重求值 (在 js 代码中执行另一段代码, 此时首先会以正常方式求值, 然后在执行过程中对包含字符串中的代码发起另一个求值运算) 带来的性能消耗给 setTimeout 和 setInterval 传递函数而不是字符串作为参数
2. 避免重复工作 (事件处理的兼容函数) 当需要检测浏览器时, 可使用延迟加载 (脚本调用时检测) 和条件预加载(脚本加载期间提前检测)
延迟加载:
- function addHandler(target,eventtype,handler){
- if(target.addEventListener){
- addHandler=function(target,eventtype,handler){
- target.addEventListener(eventtype,handler,false)
- }
- }else{
- addHandler = function (target,eventtype,handler){
- target.attachEvent(on+eventtype,handler)
- }
- }
- addHandler(target,eventtype,handler)
- }
条件预加载:
- var addHandler = document.body.addEventListener? function(target,eventtype,handler){
- target.addEventListener(eventtype,handler,false)
- } :
- function (target,eventtype,handler){
- target.attachEvent(on+eventtype,handler)
- }
3. 在进行数学计算时考虑使用自己操作数字的二进制形式的位运算
4. 尽量使用原生方法
九: 构建并部署高性能 js 应用
1. 合并 js 文件减少 http 请求量
2. 压缩 js 文件
3. 在服务端压缩 js 文件(Gzip 编码)
4. 通过正确设置 http 响应头来缓存 js 文件, 通过改变文件名的方式强制浏览器重新加载指定文件
5. 使用 CDN(content Delivery networtk)内容分发网络提供 js 文件; CDN 不仅可以提升性能, 还能管理文件的压缩与缓存
十: 构建并部署高性能 js 应用
1. 使用网络分析工具找出加载脚本和页面中其他资源的瓶颈, 帮助决定哪些脚本需要延迟加载等
2. 尽量减少 http 请求数, 把脚本尽可能延迟加载
3. 使用性能分析工具找出脚本运行过程中速度较慢的地方, 检查每个函数所消耗的时间以及函数被调用的次数, 通过调用栈自身提供的线索来找出需要集中精力优化的地方
其他:
应用实践中代码优化, 提取重用函数, 重用组件等
来源: http://www.bubuko.com/infodetail-2507098.html