资讯专栏INFORMATION COLUMN

读书笔记(03) - 性能 - JavaScript高级程序设计

warnerwu / 2994人阅读

摘要:作用域链查找作用域链的查找是逐层向上查找。而全局变量和闭包则会与之相反,继续保存,所以使用用后需手动标记清除,以免造成内存泄漏。获取元素的属性获取元素的属性等参考文档高级程序设计作者以乐之名本文原创,有不当的地方欢迎指出。

作用域链查找

作用域链的查找是逐层向上查找。查找的层次越多,速度越慢。随着硬件性能的提升和浏览器引擎的优化,这个慢我们基本可以忽略。

除了层级查找损耗的问题,变量的修改应只在局部环境进行,尽量避免在局部环境下去操作修改父级变量的值。(react/vue 单向数据流的数据传输方式)

优化方法:声明一个变量存储引用(该方法应用甚多)

不必要的属性查找
// 未优化(window.location.href 3*2 6次)
var query = window.location.href.substring(window.location.href.indexOf("?"));

// 优化后(3次,以后多次调用url,查询次数不会增加)
var url = window.location.href;
var query = url.substring(url.indexOf("?"));
url = null;

函数里面声明的变量,在函数调用栈执行后退出时,会自动清除引用。而全局变量和闭包则会与之相反,继续保存,所以使用用后需手动标记清除,以免造成内存泄漏。

优化循环

减值迭代

简化终止条件

简化循环体

使用后测试循环

减值迭代

日常应用不多,与增值迭代的区别,就在i存储的值。减值迭代i的值不断在变小,存储的空间也在变小。

但在前端极少需要遍历上万次上亿次的数据,上千上百都很少,所以这个优化可忽略。而且我们遍历的顺序一般都是从数组头部开始,所以增值迭代应用的更多。

// 增值迭代(用的较多)
for(var i = 0; i < len; i++) {
    //...
}

// 减值迭代
for(var i = len - 1; i >= 0 ; i--) {
    //...
}
简化终止条件 (常用)

终止条件应该是一个固定值判断,应避免在终止条件上做其他运算(属性查找等)。

// 未优化,每次循环都会去计算数组长度
var arr = ["HTML", "CSS", "JavaScript"];
for (var i = 0; i < arr.length; i++) {
    //...
}

// 优化后
for (var i = 0, len = arr.length; i < len; i++) {
    //...
}
// 声明了一个变量len用于储存数组长度,只会计算一次
简化循环体

循环体的代码应该着重于只需要遍历处理的代码,其他无关代码应放置到循环体外面。

后测试循环
最常用的for循环和while循环都是前测试循环。而do-while这种后测试循环,可以避免最初终止条件的计算,因此运行更快。

前测试循环(for/while),可能一次都不会执行循环体

后测试循环(do...while),至少执行一次

用确定索引值更快
// for循环遍历
var arr = ["HTML", "CSS", "JavaScript"];
for (let i = 0, len = arr.length; i < len; i++) {
    arr[i];
}

// 确定索引值
arr[0]; 
arr[1]; 
arr[2];
其他

原生方法较快(Math)

switch语句较快 (多个if情况下)

位运算符较快

TIPS: 判断优化,最可能的到最不可能的顺序组织(if/switch)

最小语句数

符合 write less, do more 的代码追求

多个变量声明合并
// 多个var声明
var name = "KenTsang";
var age = 28;
var job = "Developer";

// 合并一个var声明
var name = "KenTsang",
    age = 27,
    job = "Developer";
插入迭代值
// 优化前
var name = value[i];
i++;

// 优化后
var name = value[i++];
数组/对象字面量

创建引用类型可以使用构造函数和字面量两种方式,不过日常习惯都使用字面量,因为语句更简洁,写起来更像数据封装。

// 字面量
var arr = [1, 2, 3, 4];
var obj = {
    name: "KenTsang"
}

// 构造函数
var arr = new Array(1, 2, 3, 4);
var obj = new Object();
obj.name = "KenTsang";
DOM优化交互 最小现场更新
现场更新:一旦你需要访问的 DOM 部分是已经显示的页面的一部分,那么你就是在进行一个现场更新
文档片段

文档片段相当一个临时的占位符,只有片段中的内容会被添加到DOM上,片段本身并不会被添加。

// 代码片段标签
var ele  = document.getElementById("ul");
var fragment = document.createDocumentFragment();
var browsers = ["Firefox", "Chrome", "Opera", 
    "Safari", "IE"];

browsers.forEach(function(browser) {
    var li = document.createElement("li");
    li.textContent = browser;
    fragment.appendChild(li);
});

// 只会操作一次DOM
ele.appendChild(fragment);
innerHTML

合并插入代码一次性设置innerHTML。

// 优化前:操作多次DOM
var list = document.getElementById("myList");
for (var i=0; i < 10; i++) {
    list.innerHTML += "
  • Item " + i + "
  • "; } // 优化后:操作一次DOM var innerHtml = ""; for (var i = 0; i < 10; i++) { innerHtml += "
  • Item" + i + "
  • "; } list.innerHTML = innerHtml;
    事件代理(事件委托)

    通过事件流——冒泡机制实现代理,子元素事件触发冒泡到父元素,由父元素绑定一个事件进行统一处理,避免多个事件绑定影响性能。

    • HTML
    • CSS
    • JavaScript
    var listEle = document.getElementById("list"); listEle.addEventListener("click", function(event) { if (event.target.className.indexOf("item") > -1) { console.log(event.target.innerHTML); } }) // jquery $("#list").on("click", ".item", function(event){ console.log($(this).html()); })
    注意HTMLCollection
    任何时候要访问 HTMLCollection,不管它是一个属性还是一个方法,都是在文档上进行一个查询,这个查询开销很昂贵。
    // 一个死循环例子
    link
        
    var existLinkEle = document.getElementsByTagName("a");
    for (var i = 0; i < existLinkEle.length; i++) {     
        console.log(i);
        var linkEle = document.createElement("a");
        document.body.appendChild(linkEle);
    }
    // body会不断地插入a标签

    因为existLinkEle.length每次循环都会重新计算页面a节点的数量,而得到的值一直递增。

    // 优化(一个变量存储引用)
    var len = existLinkEle.length;
    for (var i = 0; i < len; i++) {
        //...
    }

    返回HTMLCollection对象情况有:

    document.getElementByTagName()

    获取元素的childNodes属性

    获取元素的attributes属性

    document.forms,document.images

    参考文档

    《JavaScript高级程序设计》

    作者:以乐之名
    本文原创,有不当的地方欢迎指出。转载请指明出处。

    文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

    转载请注明本文地址:https://www.ucloud.cn/yun/99702.html

    相关文章

    • <javascript高级程序设计>第十二章读书笔记----偏移量

      摘要:包括元素的高度上下内边距上下边框值,如果元素的的值为那么该值为。该值为元素的包含元素。最后,所有这些偏移量都是只读的,而且每次访问他们都需要重新计算。为了避免重复计算,可以将计算的值保存起来,以提高性能。 offsetHeight 包括元素的高度、上下内边距、上下边框值,如果元素的style.display的值为none,那么该值为0。offsetWidth 包括元素的宽度、左...

      dayday_up 评论0 收藏0
    • 读书笔记(05) - 事件 - JavaScript高级程序设计

      摘要:而事件分为个级别级事件处理程序,级事件处理程序和级事件处理程序。级中没有规范事件的相关内容,所以没有级事件处理。 showImg(https://segmentfault.com/img/bVburYR?w=499&h=400); HTML依托于JavaScript来实现用户与WEB网页之间的动态交互,接收用户操作并做出相应的反馈,而事件在此间则充当桥梁的重要角色。 日常开发中,经常会...

      tinylcy 评论0 收藏0
    • 002-读书笔记-JavaScript高级程序设计 在HTML中使用JavaScript

      摘要:文件内部使用使用到的代码引入外部文件外部代码的地址标签的位置一般情况下,标签的位置放在标签中引入代码页面结构对于需要引入很多的中间,如果把放在头部,无疑会导致浏览器呈现页面出现延迟,就是导致页面出现空白。页面结构引入代码 这篇笔记的内容对应的是《JavaScript高级程序设计(第三版)》中的第二章。 1.使用方式 在HTML中使用 JavaScript 的方式有两种,第一种就是直接内...

      banana_pi 评论0 收藏0
    • 001-读书笔记-JavaScript高级程序设计 JavaScript简介

      摘要:由于计算机的国际化,组织的标准牵涉到很多其他国家,因此组织决定改名表明其国际性。规范由万维网联盟制定。级标准级标准是不存在的,级一般指的是最初支持的。 这篇笔记的内容对应的是《JavaScript高级程序设计(第三版)》中的第一章。 1.ECMA 和 ECMA-262 ECMA 是欧洲计算机制造商协会的缩写,全程是 European Computer Manufacturers Ass...

      masturbator 评论0 收藏0
    • JavaScript高级程序设计》(第3版)读书笔记 第1~2章

      摘要:表示应该立即下载脚本,但不应妨碍页面中的其他操作可选。表示通过属性指定的代码的字符集。表示脚本可以延迟到文档完全被解析和显示之后再执行。实际上,服务器在传送文件时使用的类型通常是,但在中设置这个值却可能导致脚本被忽略。 第1章 JavaScript 简介 虽然JavaScript和ECMAScript通常被人们用来表达相同的含义,但JavaScript的含义比ECMA-262要多得多...

      Corwien 评论0 收藏0

    发表评论

    0条评论

    warnerwu

    |高级讲师

    TA的文章

    阅读更多
    最新活动
    阅读需要支付1元查看
    <