Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[歸納] JavaScript 之高性能 #27

Open
aleen42 opened this issue Mar 1, 2017 · 0 comments
Open

[歸納] JavaScript 之高性能 #27

aleen42 opened this issue Mar 1, 2017 · 0 comments

Comments

@aleen42
Copy link
Owner

aleen42 commented Mar 1, 2017

image

最近,在啃一本为人所熟知的动物书《[O`Reilly] - High Performance JavaScript - [Zakas]》。本书中,作者主要以四大角度去谈及 JavaScript 如何在性能上得以提高。为了能使其变为我自身 JavaScript 知识体系中的一部分,我以自己的语言去加以总结,并归档于此链接。(虽是英文,但描述得非常直白,希望大家不要害怕。)

在此,我希望通过这个 Issue,以中文的形式从更高的层次去总结所有的性能提升技巧以方便记忆与查询(但是细节也要深入去理解与学习,而非得过且过):

1. JavaScript 的加载

作者就此角度主要谈及如何去高效地加载与执行 JavaScript 代码。正因其执行过程会产生阻塞问题,因此我们需要通过若干方式去最小化该性能影响:

  • 尽可能地把所有的 script 标签置于页面的底部,即 body 标签内的末尾部分。
  • 使用构建工具把多个 script 组合在一起
  • 使用以下地方式去异步加载 JavaScript 代码:
    • 添加 defer 属性可预加载 JavaScript 代码并等到页面加载渲染完成后及 onload 事件触发之前执行
    • 以代码的方式动态加载 script
    • 通过 XMLHttpRequest 来加载 script

[详情]

2. 编码技巧

以优雅的编码技巧去提高性能会涉及到几个方面,如数据访问方式、DOM 相关编码或代码结构等。经过此章的阅读,个人认为这些技巧并不仅仅针对于 JavaScript 语言,而是作为一种更高层次的编程哲学去浸染开发者的编程思想,从而在骨子里下意识地提高代码的优雅程度。

2.1 数据访问

首先,作者开篇所讲的是关于数据的访问,并区分出四种访问的方式:对字面值的访问、对变量的访问、对数组成员的访问以及对对象成员的访问。当然,访问的快慢也是与这顺序所相对应的。

  • 字面值与变量的访问比数组及对象的访问要快
  • 访问本地变量要比访问外部变量要快
  • 尽可能不使用 withtry-catcheval().
  • 减少对象成员的嵌套
  • 访问对象成员时,查找的原型链越长越消耗更多的时间
  • 闭包不仅会占用内存,而且在低版本浏览器中导致内存泄漏,因此要权衡。

[详情]

2.2 DOM 编程

第二,关于 DOM 相关的编程,我们要谨记一点:DOM 的访问及操作犹如搭载在桥梁上的收费站,太多的访问与操作只会带来性能上的消耗。因此:

  • 我们应该尽可能地减少对 DOM 元素的访问,而把工作放在 JavaScript 代码中去执行
  • 若需要重复操作 DOM 元素,则把其对应的引用存储在一个本地变量
  • document.getElementsByName()document.getElementsByClassName()document.getElementsByTagName() 等方法所放回的是一个 HTML Collections。遍历该集合时我们需要考虑到,若该集合不怎么大时,我们可以把集合的大小缓存在一个本地变量以作循环条件中的判断;而若集合非常大时则需要考虑把其转换成数组来遍历
  • 若浏览器支持时,尽可能地使用更为高效的封装属性或函数,如 firstElementChilddocument.querySelectorAll() 等。
  • 尽可能地去减少页面的重排与重绘
  • 在制作动画时,应把元素先置为绝对定位,以减少重排及重绘所带来的消耗
  • 使用事件委托机制来减少事件处理函数的数量

[详情]

2.3 代码中的算法及代码流的控制

个人认为,为何我们写的代码总运行得这么慢?主要原因在于我们的算法不够高效,而且代码流的控制不够优雅。所执行的代码越多,执行的时间也就越长。因此不管是循环结构还是控制结构,作者都给出了自己的经验之谈:

  • forwhile 以及 do-while 结构都非常相似,并没说哪种循环结构更为高效
  • 除非需要遍历一个属性未知的对象,不然请不要轻易使用 for-in 结构
  • 尽可能地减少循环的次数及每次循环的工作量,以优化循环
  • 尽管 switch 结构比 if-else 结构要高效,但并非是一个最佳的选择
  • 对于代码有多种流向的情况,Lookup 表是一种不错的选择
  • 当算法涉及到递归时,请注意各浏览器中栈使用量的限制
  • 当递归算法超出栈使用量的限制时,尝试使用循环去替代算法或通过记忆的手段减少重复计算的次数

[详情]

2.4 字符串及正则表达式

频繁的字符串操作与不严格的正则表达式都会产生重大的性能问题,因此我们需要谨记以下几点:

  • 当需要拼接非常多或非常长的字符串时,有理由相信 Array.join() 是你的首选方式
  • 如果你不需要考虑到低版本浏览器如 IE7 或以下版本,那么你就可以选择使用简单的 ++= 操作符来实现拼接
  • 使用正则表达式时,失控的 backtracking 都会导致浏览器崩溃,因此我们要加以小心
  • 当你是对已知的字符串进行操作时,请不要轻易使用正则表达式
  • 我们可以结合两个简单的正则表达式来实现字符串的 trim 操作,但若您需要考虑到字符串的长度时,末尾的 trim 最好是由遍历来实现

[详情]

2.5 页面响应

通常我们都知道,一个页面的 UI 更新是与 JavaScript 代码的执行共享同一条进程。这也就意味着不能同时执行代码和更新页面。因此为了不影响用户的体验,我们最好:

  • 尽可能地保持代码执行时间不超过 100 毫秒
  • 若算法复杂且任务执行时间无法再压缩,那么可以考虑使用 timer 函数即 setTimeout()setInterval() 来分解任务
  • Web Workers 是 HTML5 所提出的新特性。它可以使得我们在一个独立的线程上执行代码来处理与 UI 无关的任务,如大型 JSON 的解析等

[详情]

2.6 Ajax

若想采用高性能的 Ajax 技术,也许你需要清楚自己的开发需求并根据它们来选择最合适的数据格式及传输方式。

对于数据格式来说:

  • 纯文本和 HTML 格式的数据虽然很特殊,但是却能节省了不少的 CPU 计算资源
  • XML 之前虽被广泛运用,但是却暴露出冗长及解析慢的缺点
  • JSON 相对于 XML 来说,简单且解析快
  • 若你想传输大量的数据,那么理应前后端制定好自定义格式来格式化数据,如采用分隔符

当我们需要请求数据时:

  • 使用 XHR 能更为深入地操纵传输过程的细节,如请求头的设置等。但由于是以字符串形式来处理应答,以致于解析速度下降
  • 使用动态 script 标签注入,可请求跨域资源且以 JavaScript 或 JSON 的形式直接解析,但需要考虑安全问题
  • MXHR 可以在加载多个资源时减少请求,但无法缓存

倘若是往服务器发送数据:

  • 设置 Image 对象的 src 属性会是一种高效简便的方法
  • 但如果你需要传输大量的数据时,只能使用 XHR 进行 POST 请求以避免 GET 请求中 URL 过长所导致问题

除此之外,还有一些提升性能的技巧需要我们注意:

  • 通过拼接文件或采用 MXHR 技术来减少网络请求
  • 使用 Ajax 技术可降低页面初始化时的加载时间

[详情]

2.7 编程中的一些细节

谈及性能优化,我们理应先从我们的代码入手:

  • 为了避免二次计算,尽可能不使用 eval()Function() 构造器来执行代码。而且,使用 setTimeout()setInterval() 时,第一个参数应该传递函数,而非字符串
  • 直接使用 []{} 来创建数组和对象
  • 在浏览器兼容性判断时,采取 lazy loading 或 conditional advance loading 两种策略来优化判断的过程
  • 当进行算术运算时,优先考虑按位操作
  • 尽可能使用 JavaScript 原生已实现的方法

[详情]

3. 代码的构建与部署

如今 JavaScript 代码的构建工具层出不穷,Webpack、Gulp 等早已为人熟知,然而在使用这些辅助性工具之前,我们必须明白在构建与部署的过程中,一些细节往往会对应用的性能提升产生不可或缺的影响,如:

  • 合并多个 JavaScript 资源以减少 HTTP 请求的数量
  • 使用类似 YUI Compressor 的工具去压缩 JavaScript 文件
  • 致力于 JavaScript 资源的压缩(如允许 gzip 压缩)
  • 设置部分 HTTP 请求头来缓存资源
  • 尽量把资源部署于 CDN 节点,以减少网络延迟

[详情]

To be continued ...

@aleen42 aleen42 self-assigned this Mar 1, 2017
@aleen42 aleen42 changed the title [归纳] JavaScript 之高性能 [歸納] JavaScript 之高性能 Mar 19, 2018
aleen42 referenced this issue Apr 19, 2019
Former-commit-id: 0c3ad91
Former-commit-id: 025b23d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant