美文网首页前端开发程序员让前端飞
(更新中)【前端性能优化】高性能JavaScript读书笔记

(更新中)【前端性能优化】高性能JavaScript读书笔记

作者: 番茄沙司a | 来源:发表于2019-03-19 23:05 被阅读0次
    封皮一隅

    曾经看过一篇文章,有一句话这样说:

    只有在大学的图书馆里,你才能真正赚回你交的学费。

    临近毕业,还想再去图书馆多转转。偶然在架子上发现了这本书,一看作者是写大名鼎鼎的红宝书的人,就很感兴趣。再者,最近用 JavaScript 刷 LeetCode 发现,提交显示 JavaScript 要比 Go 语言或 Python 有更大的时间和内存消耗,也使我把了解 JavaScript 内存机制和性能优化提上了日程。

    本书虽然有部分章节涉及到的问题有一定年代感,比如最后一章[工具],由于前端技术的快速迭代和浏览器的不断支持下,已经不适用了。但是这本书的前面章节详细地从js运行、访问、代码结构优化、异步编程等多方面讲解了 JavaScript 优化的策略,解答了我刷题时的疑惑,也让我认识到之前秋招面试的时候遇到的一些坑,还是有许多需要引起重视的知识体系需要不断扩容。

    总之,这本书是对前端性能优化基础知识的一种补充掌握,推荐有项目经验并希望提升Web应用性能的前端开发人员阅读。

    前端性能优化

    下面是我认知的前端性能优化的策略,本书主要着手 JavaScript 优化展开阐述。

    • JavaScript优化
    • 非核心代码异步加载
    • 浏览器缓存
    • 使用CDN
    • DNS预解析
    • 优化资源
    • 清理不必要的依赖

    正文

    一、浏览器中的 JavaScript

    浏览器中js代码的执行可能会阻塞浏览器的其他进程,下边列出了几点棘手的问题以及优化方式。

    1. 脚本阻塞:将<script>标签放在页面底部,</body>闭合标签之前。

    2. 延迟时间:

      1. 内嵌<script>不紧跟<link>标签
      2. 运用打包工具,合并js文件
    3. 无阻塞加载js:关键是在window对象的load事件触发后再下载脚本

      1. 使用<script>标签的defer属性
        注意:defer属性仅当src属性声明时才生效

      2. 动态脚本加载:使用动态创建的<script>元素来下载并执行代码
        注意:需要通过侦听事件,跟踪并确保脚本下载完成并准备就绪
        优势是跨浏览器兼容性和易用,也是最通用的无阻塞加载的策略。

      3. 使用 XHR 对象下载 JavaScript 代码并注入页面中

        局限性:JavaScript 文件必须和所请求的页面同域,不适用大型Web项目。

    无阻碍脚本加载工具:YUI3、LazyLoad、LABjs

    通过以上策略,可以极大地提高JavaScript的Web应用的性能。
    此外,还有一些策略例如:减少js文件的大小、限制HTTP请求数。这两点策略,随着Web应用的日益复杂,可行性也随之降低,也不是做的越极致效果越好,需要实际情况具体分析。

    二、数据存储的位置

    数据存储的位置关系到数据的检索速度,直接影响代码执行的效率。JavaScript 有以下四种基本的数据存储位置:

    1. 字面量:值的记法,包括:字符串、数字、布尔值、对象、数组、函数、正则表达式,还有特殊的 null 和 undefined 值
    2. 本地变量:使用 var/let/const 关键字定义的数据存储单元
    3. 数组元素:以数字为索引,存储在 JavaScript 数组对象内部
    4. 对象成员:以字符串作为索引,存储在 JavaScript 对象内部
    标识符解析的性能

    在函数的执行过程中,每遇到一个变量,都会经历一次标识符解析过程以决定从哪里获取或存储数据。该过程的搜索执行环境是作用域链,这个搜索过程会影响性能。

    注意:总的趋势是,标识符所在位置越深,它的读写速度越慢。若采用优化过的 JavaScript 引擎的浏览器性能损失会大大减少。

    原型链和嵌套成员也遵从此关系。

    注意作用域链的改变

    可以在执行时改变作用域链,影响性能的语句:

    1. with 语句:会导致一个新的变量对象被置于作用域链的首位,造成访问特定对象的属性非常快,而访问局部变量则变慢。
      建议:弃用

    2. try-catch语句中的 catch 子句:会把异常对象推入一个变量对象并置于作用域的首位。
      建议:将错误委托给一个函数处理

    闭包

    闭包的[[scope]]属性包含了与执行环境作用域链相同的对象的引用,同时会影响内存开销和执行速度,应小心使用闭包。

    策略

    可以通过把常用的数组元素、跨域变量保存在局部变量中来改善性能。

    这种策略不推荐用于对象的成员方法,会改变this的值。

    三、DOM 编程

    浏览器中通常会把 DOM 和 JavaScript 独立实现,所以访问DOM元素消耗很大。

    策略:减少访问DOM的次数,把运算留给ECMAScript一端。

    innerHTML 对比 DOM 方法

    旧版浏览器中,使用innerHTML会更快一些。在基于 WebKit 内核的新版浏览器中,用DOM略胜一筹。

    策略:根据可读性、稳定性、团队习惯、代码风格来综合决定。

    节点克隆

    节点克隆element.cloneNode()比创建新元素document.createElement更有效率,但不明显。

    HTML集合

    返回值是集合的方法:

    • document.getElementByName()
    • document.getElementByClassName()
    • Document.getElementByTagName()

    返回值是集合的属性:

    • document.images
    • document.links
    • document.forms
    • document.forms[0].elements

    HTML集合是包含DOM节点引用的类数组对象。和数组的区别是没有push和slice方法,有length属性和数字索引的方式访问元素。

    HTML集合低效之源:假定实时态 assumed to be live

    策略:

    1. 把集合的长度缓存到一个局部变量中,在循环条件的退出语句中使用该变量。

    2. 使用数组拷贝。

      function toArr() {
          for (var i = 0, arr = [], len = coll.length; i < len; i++) {
              arr[i] = coll[i];
          }
          return arr;
      }
      
    遍历DOM
    属性名 被替代的属性
    children childNodes
    childElementCount childNodes.length
    firstElementChild firstChild
    lastElementChild lastChild
    nextElementSibling nextSibling
    previousElementSibling previousSibling
    选择器API

    queryAelectorAll()方法使用CSS选择器作为参数并返回一个NodeList,不会返回HTML集合。适合处理大量组合查询。

    相关文章

      网友评论

        本文标题:(更新中)【前端性能优化】高性能JavaScript读书笔记

        本文链接:https://www.haomeiwen.com/subject/qijomqtx.html