前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript性能提升学习

JavaScript性能提升学习

作者头像
csxiaoyao
发布2019-02-15 16:41:17
1.3K0
发布2019-02-15 16:41:17
举报
文章被收录于专栏:csxiaoyao

JavaScript性能提升学习

1 提升js加载与执行性能

  1. 多数浏览器使用单一进程处理UI和js脚本执行,部分浏览器允许并行下载js文件,但仍会阻塞其他资源下载,比如图片,页面仍必须等到所有js代码下载执行完才能继续,内嵌脚本不要跟在后,将会导致页面阻塞等待样式表的下载
  2. 减少<script>标签的数量,包括内嵌和外链脚本,最小化执行延迟会明显改善页面性能, 方式一:合并 方式二:
代码语言:javascript
复制
<script type="text/javascript" src="http://yui.yahooapis.com/combo?2.7.0/build/yahoo/yahoo-min.js&2.7.0/build/event/event-min.js "></script>
  1. 无阻塞下载js文件 3.1 defer延迟脚本,兼容性不佳,代码仍会下载,但会等到DOM加载完,onload事件触发前执行
代码语言:javascript
复制
<script defer>
    alert("defer");
</script>
<script>
    alert("script");
</script>
<script>
    window.onload = function(){
        alert("load");
    };
</script>

不支持defer属性的浏览器:defer、script、load 支持defer属性的浏览器:script、defer、load 3.2 动态添加script标签,添加到head中比添加到body中安全 3.3 XHR动态脚本注入兼容性好,但不能跨域

代码语言:javascript
复制
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.createElement("script");
            script.type = "text/javascript";
            script.text = xhr.responseText;
            document.body.appendChild(script);
        }
    }
};
xhr.send(null);

3.4 推荐的方式

代码语言:javascript
复制
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 { //Others
        script.onload = function(){
            callback();
        };
    }
    script.src = url;
    document.getElementsByTagName("head")[0].appendChild(script);
}
loadScript("the-rest.js", function(){
    Application.init();
});

3.5 LazyLoad类库实现懒加载

2 提升js数据存取性能

2.1 管理作用域

  1. 尽量使用字面量和局部变量,减少数组项和对象成员的使用
  2. 管理作用域链,将全局变量的引用存储在局部变量中,用局部变量代替全局变量,将全局变量的访问次数从多次改为1次,数量越大,效果越明显(with和try/catch中的catch可改变执行环境作用域链,但不推荐)
代码语言:javascript
复制
var doc = document;
doc.X……
doc.XX……
doc.XXX……
  1. 闭包的[[scope]]属性包含了与执行环境作用域相同的对象的引用,且不会随函数的执行环境活动对象的销毁一同销毁,此外,频繁调用存在跨作用域变量存在性能问题,解决方法为使用局部变量存储跨作用域变量。

2.2 对象成员

  1. js中的对象基于原型,对象通过一个内部属性(proto)绑定到它的原型,hasOwnProperty()只在当前对象查找是否包含该属性,in操作符则可以同时搜索实例及其原型
  2. 原型链中搜索实例成员比从字面量或局部变量中读取代价更高,且嵌套越深,代价越高,location.href比window.location.href快,而后者又比window.location.href.toString()快,可以利用局部变量减少对对象成员的读写

3 DOM编程

3.1 DOM操作

  1. DOM的访问与修改较慢,通用的经验法则是:最小化DOM访问次数,把运算尽量留在ECMAScript端处理
  2. innerHTML比document.createElement()的原生DOM方法在大多数浏览器中略快,cloneNode比createElement略快。
  3. HTML集合(document.getElementsByName()/ClassName()/TagName()、document.images/links/forms/forms[0].elements的返回值)是类似数组的列表,因为没有数组的方法,却又类似数组的length属性,并且能以索引方式访问。
  4. HTMLCollection一直与文档保持连接,当需要最新信息时会重复执行查询的过程,即使只是获取集合元素(length属性)
代码语言:javascript
复制
var alldivs = document.getElementsByTagName('div');
for (var i = 0; i < alldivs.length; i++) {
    document.body.appendChild(document.createElement('div'))
}

这个例子反映了集合的动态性,此处为死循环,因为alldivs.length是不断更新的,并且速度相比直接查询数组length慢很多,因为length每次都要重新查询。优化方法:1、把HTMLCollection存储在局部变量数组中;2、把length缓存在循环外部。 5. 在IE中,nextSibling比childNode表现优异,选择过滤非元素节点的api效率更高。

代码语言:javascript
复制
属性名                     被替代的属性
children                        childNodes
childElementCount           childNodes.length
firstElementChild           firstChild
lastElementChild            lastChild
nextElementSibling          nextSibling
previousElementSibling      previousSibling
  1. 如果可能,使用速度更快更简洁的api
代码语言:javascript
复制
document.querySelector('#menu a');

3.2 重绘与重排

  1. 浏览器下载完页面中所有组件后会解析并生成两个内部数据结构:DOM树、渲染树,重绘与重排代价非常昂贵,应尽量避免
  2. offset/scroll/clientTop/Left/Width/Height会强制执行渲染队列中的“待处理变化”并触发重排以返回正确的值,应尽量避免直接使用,而是缓存布局信息
  3. 四种“离线”优化思路 (1) 合并对样式的改变,一次性修改DOM; (2) 隐藏元素,应用修改,重新显示; (3) 使用文档片段在当前DOM外构建一个子树,再拷贝回文档; (4) 使元素脱离文档流,克隆,修改副本,替换原始元素
  4. 动画:例如展开/折叠动画,大规模重排会有卡顿感,优化: (1) 绝对定位脱离文档流; (2) 添加动画,临时覆盖部分页面; (3) 动画结束,下移到标准流,恢复定位,重绘与重排一次
  5. IE中尽量减少使用:hover,优化性能

3.3 事件委托

减少事件处理器数量,利用了事件三个阶段:捕获–>到达目标–>冒泡 中的最后一个阶段。在父元素绑定事件,实现对子元素的事件监听,需要实现一堆浏览器兼容代码,流程:1、访问事件对象,判断事件源;2、取消文档树中的冒泡(可选);3、阻止默认操作(可选)

4 算法和控制流程

4.1 循环

  1. 四种循环:for、while、do-while、for-in,for-in明显较慢 倒序遍历数组能够提升性能,因为简化了控制条件的判断,(k–)到0自动停止,数值型可以自动转换boolean型,不用写成(k

4.2 条件语句

通常情况下, switch比if-else快,switch适合于使用一系列的操作的场景,当单个键和单个值存在逻辑映射且判断条件较多时,使用查找表(数组映射)比使用if-else/switch效率更高

4.3 递归

浏览器的调用栈大小限制了递归的使用规模,尽量使用迭代代替递归 栈溢出错误的解决方式: 使用try-catch捕获

代码语言:javascript
复制
try{
    // 递归程序
}catch(e){}

5 字符串和正则表达式

  1. 当连接数量巨大或尺寸巨大的字符串时,数组项合并是唯一在IE7及更早版本中性能合理的方法。如果不考虑IE7及更早版本的性能,数组项合并是最慢的数组项合并方法之一,推荐使用+或+=操作符代替,避免不必要的中间字符串
  2. 部分匹配比完全不匹配所用时间长
  3. 回溯既是正则表达式匹配功能的基本组成部分,也是正则表达式的低效之源
  4. 优化:使相邻字元互斥,避免嵌套量词对同一字符串的相同部分匹配多次,通过重复利用预查的原子组去除不必要的回溯
  5. trim的浏览器兼容的高效混合解决方案
代码语言:javascript
复制
String.prototype.trim = function(){
    var str = this.replace(/^\s+/,""),
        end = str.length - 1,
        ws = /\s/;
    while(ws.test(str.charAt(end))){
        end--;
    }
    return str.slice(0,end+1);
}

6 快速响应的用户界面

代码语言:javascript
复制
function timedProcessArray(items,process,callback){
    var todo = items.concat(); // 克隆原始数组
    setTimeout(function(){
        var start = +new Date();
        do{
            process(todo.shift());
        }while(todo.length > 0 && (+new Date()-start<50));
        if(todo.length>0){
            setTimeout(arguments.callee,25);
        }else{
            callback(items);
        }
    },25);
}
  1. JavaScript任务的执行不应超过100ms
  2. 定时器能够用来安排代码延迟执行,可以把长时间运行脚本分解成一系列小任务
  3. Web Workers是新版浏览器支持的特性,允许在UI线程外执行js代码,从而避免锁定 (略……)

7 Ajax

7.1 请求数据的五种常用技术

【常用】: 1. XMLHttpRequest (XHR): 收到的所有数据当成一个字符串,可能降低解析速度 2. Dynamic script tag insertion 动态脚本注入(跨域) 3. Multipart XHR (MXHR) 优点:客户端一个HTTP请求从服务器端获取多个资源(http请求对ajax的性能影响极大) 缺点:浏览器无法缓存资源、老版本IE不支持 readyState==3 和 data:URL

代码语言:javascript
复制
// 实时处理请求响应数据
var req = new XMLHttpRequest();
var getLatestPacketInterval, lastLength = 0;
req.open('GET', 'rollup_images.php', true);
req.onreadystatechange = readyStateHandler;
req.send(null);
function readyStateHandler{
    // 传输中
    if (req.readyState === 3 && getLatestPacketInterval === null) {
        // Start polling.
        getLatestPacketInterval = window.setInterval(function() {
            getLatestPacket();
        }, 15);
    }
    // 传输结束
    if (req.readyState === 4) {
        // Stop polling.
        clearInterval(getLatestPacketInterval);
        // Get the last packet.
        getLatestPacket();
    }
}
function getLatestPacket() {
    var length = req.responseText.length;
    var packet = req.responseText.substring(lastLength, length);
    processPacket(packet);
    lastLength = length;
}

编写健壮的MXHR代码较为复杂,此处略过……

【极端】: 4. iframes 5. Comet

7.2 发送数据

  1. XHR GET方式更快,get只发一个数据包,post发两个数据包(头、正文)
代码语言:javascript
复制
req.onerror = function() {
    setTimeout(function() {
        xhrPost(url, params, callback);
    }, 1000);
};

请求失败时重发数据有利于用户体验 2. 信标(beacons)

7.3 数据格式

  1. XML: 支持良好,但笨重且解析慢
  2. JSON: 数组形式的json解析速度更快
  3. JSON-P: 动态脚本注入 区分json与jsonp,二者原理不同,jsonp是json的一种使用模式 ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本
  4. HTML: 传输极慢,但可以节省客户端CPU周期
  5. 自定义格式:字符分隔的自定义格式例如使用 “;”, 使用split解析,效率高,数据尺寸小

7.4 Ajax性能优化:缓存数据

  1. 服务器端:设置HTTP头信息,确保响应被浏览器缓存 (1) 必须使用GET请求 (2) 设置Expires头信息
  2. 客户端:把获取到的信息存储本地,避免再次请求
代码语言:javascript
复制
var localCache = {};
function xhrRequest(url, callback) {
    // Check the local cache for this URL.
    if (localCache[url]) {
        callback.success(localCache[url]);
        return;
    }
    // If this URL wasn't found in the cache, make the request.
    var req = createXhrObject();
    req.onerror = function() {
        callback.error();
    };
    req.onreadystatechange = function() {
        if (req.readyState == 4) {
            if (req.responseText === '' || req.status == '404') {
                callback.error();
                return;
            }
            // Store the response on the local cache.
            localCache[url] = req.responseText;
            callback.success(req.responseText);
        }
    };
    req.open("GET", url, true);
    req.send(null);
}
代码语言:javascript
复制
delete localCache['/user/friendlist/'];
delete localCache['/user/contactlist/'];

8 编程实战

8.1 避免双重求值

避免使用 eval()、Function(),给setTimeout()、setInterval()传递函数作为参数而非字符串

8.2 使用Object/Array直接量

{}、[] 速度更快且代码简洁

8.3 避免重复工作

使用延迟加载、条件预加载

8.4 使用位操作和原生方法

尤其是数学运算与DOM操作

9 构建并部署高性能的JavaScript应用

合并js文件减少请求数、使用YUI Compressor压缩js文件、服务器端压缩js代码(Gzip)、设置http响应头缓存js文件、使用CDN

10 工具

10.1 性能分析

10.2 网络分析

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017年05月10日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JavaScript性能提升学习
    • 1 提升js加载与执行性能
      • 2 提升js数据存取性能
        • 2.1 管理作用域
        • 2.2 对象成员
      • 3 DOM编程
        • 3.1 DOM操作
        • 3.2 重绘与重排
        • 3.3 事件委托
      • 4 算法和控制流程
        • 4.1 循环
        • 4.2 条件语句
        • 4.3 递归
      • 5 字符串和正则表达式
        • 6 快速响应的用户界面
          • 7 Ajax
            • 7.1 请求数据的五种常用技术
            • 7.2 发送数据
            • 7.3 数据格式
            • 7.4 Ajax性能优化:缓存数据
          • 8 编程实战
            • 8.1 避免双重求值
            • 8.2 使用Object/Array直接量
            • 8.3 避免重复工作
            • 8.4 使用位操作和原生方法
          • 9 构建并部署高性能的JavaScript应用
            • 10 工具
              • 10.1 性能分析
              • 10.2 网络分析
          相关产品与服务
          内容分发网络 CDN
          内容分发网络(Content Delivery Network,CDN)通过将站点内容发布至遍布全球的海量加速节点,使其用户可就近获取所需内容,避免因网络拥堵、跨运营商、跨地域、跨境等因素带来的网络不稳定、访问延迟高等问题,有效提升下载速度、降低响应时间,提供流畅的用户体验。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档