将样式表放在顶部

把你的样式放在 head 标签中。
不要使用 @import 加载你的样式表,它会在最后加载导致页面出现白屏现象。

将脚本放在底部

脚本下载时并行下载禁用,因为脚本可能使用 document.write 来修改页面内容,也是为了保证脚本能够按照正确的顺序执行。

避免 CSS 表达式

CSS Expression,动态 CSS 属性,IE 私有,自 5.0 开始引入(IE8 将不再支持)不要使用

优点

  • 使 CSS 属性动态生成,所以基本 js 能干的它都能干
  • 使用 CSS 选择符,比 js 遍历到某个特定元素要方便得多

缺点

expression 会反复执行,有严重的效率问题。它的触发似乎不是通过事件,而是通过 interval 一类的机制。
别的浏览器不支持,IE8 也将不再支持

使用外部 JavaScript 和 CSS

使用外部 JavaScript 和 CSS 有机会被浏览器缓存起来

减少 DNS 查找

DNS 缓存会影响服务器的性能,你需要设置合适的 TTL 的值。减少唯一主机名会减少 DNS 查找的数量,但是会减少并行下载的数量。所以使用 2-4 个主机名是比较合适的做法。使用 Keep-Alive 重用现有连接也会减少 DNS 的查找。

DNS 预解析

  1. <link rel="dns-prefetch" href="//libs.cdnjs.net">
  2. <link rel="dns-prefetch" href="//tjs.sjs.sinajs.cn">
  3. <link rel="dns-prefetch" href="//blog-1257169527.file.myqcloud.com">

引擎渲染和浏览器

  1. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  2. <meta name="renderer" content="webkit">

精简 JavaScript

精简

从代码中移除不必要的字符减少其大小,进而改善加载时间的实践。在代码被精简后,所有的注释和不必要的空白字符都被移除。对于 CSS 使用 0 代替 0px,使用 #606 代替 #660066。

混淆

移除空白和注释,同时改写代码。作为改写的一部分,函数和变量的名称都会被替换为更短的字符串,这时代码更加精简也更难阅读。这样做是为了增加反向工程的难度,对提高性能也有帮助。

缺陷

由于混淆更为复杂,混淆过程中可能引入错误。

维护

由于混淆会改变 JavaScript 符号,因此需要对任何不能改变的符号进行标记,防止混淆时修改它们。

调试

混淆的代码难以阅读,调试变得困难。

理解 Ajax 性能

减少迭代的开销、次数或者重新设计应用程序。减少循环的嵌套或者更换算法。
浏览器通常在 JavaScript 上花费的时间很少,绝大多数时间都消耗在 DOM 上。

创建快速响应的 Web 应用

怎么才算快

  • 0.1 秒:用直接操作 UI 中的对象的感觉极限。
  • 1 秒:用户随意地在计算机指令空间进行操作而无需过度等待的感觉极限。超过 1 秒但不到 10 秒的延时要提示用户计算机正在解决这个问题。
  • 10 秒:用户专注于任务的极限。超过 10 秒的任何操作需要一个百分比完成进度的指示器。

确保响应速度

一旦确定代码的性能不好并且无法优化它时,可以使用 Web Workers。

拆分初始化负载

将要下载的 JavaScript 拆分为两个部分,一部分用于页面初始化,另一部分则可以延时加载。

无阻塞加载脚本

Script DOM Element

  1. var sriptElem = document.createElement('script');
  2. scriptElem.src = 'htttp://anydomain.com/A.js';
  3. document.getElementByName('head')[0].appendChlid(scriptElem);

Script Defer

下载设置 defer 属性的脚本时,允许其它脚本下载。

  1. <script defer src="htttp://anydomain.com/A.js"></script>

Script Async

对于没有任何依赖的 JS 文件可以加上 async 属性,表示 JS 文件下载和解析不会阻塞渲染。

整合异步代码

异步代码可能会和行内代码之间存在代码依赖关系。JavaScript 下载完成的时间不确定,可能造成出现依赖代码没有加载完成,出现竞争态。异步加载代码保持执行顺序的最佳方式是使用 Script Onload。行内代码可以在外部代码加载完成后立即执行。

布置行内脚本

避免行内代码阻塞并行下载的方案:

  • 把行内代码移至底部。
  • 使用异步回调启动 JavaScript 的执行。
  • 使用 script 的 defer 属性。

样式表后面的行内脚本会阻止所有后续资源的下载。

编写高效的 JavaScript

管理作用域

标识符在作用域链中查找和访问它所需的时间长,会给脚本的执行时间带来负面影响。

使用局部变量

  • 局部变量是 JavaScript 读写最快的标识符。
  • 任何非局部变量在函数中使用超过一次,都应该将其储存为局部变量。
  • 全局变量始终是作用域中最后一个对象,所以全局标识符的解析总是最耗时的。

高效的数据读取

脚本有 4 种地方可以读取数据:

  • 字面量值
  • 变量
  • 数组元素
  • 对象属性

image.png

流控制

快速条件判断

  • 使用 if 语句
    • 一两个判断。
    • 大量的值能很容易区分到不同的区间。
  • 使用 switch 语句
    • 超过两个而少于 10 个离散值需要判断。
    • 条件值是非线性的,无法分离出区间范围。
  • 使用数组查询
    • 超过 10 个值需要判断
    • 条件对应的结果是单一的,而不是一系列操作。

快速循环

  • 使用 var length = values.length 代替 values.length 可以避免每次都进行属性查找。
  • 避免 for-in 循环

避免运行时间过长的脚本

一般而言脚本执行不能超过 100 毫秒。常见的脚本执行时间过长的原因包括:

  • 过多的 DOM 交互
  • 过多的循环
  • 过多的递归

使用定时器挂起

当脚本运行需要花太长时间运行的时候,就让部分延时执行。过小的延时会引起浏览器不响应,一般而言延时 50-100 毫秒是合适的,这足够让浏览器有时间执行必要的页面更新。

参考

【1】高性能网站建设进阶指南:Web 开发者性能优化最佳实践
【2】高性能网站建设指南:前端工程师技能精髓