# 性能指标
# lightHouse
- First Contentful Paint (首次渲染)
 - Speed Index (速度指数,所有内容看到)
 - Largest Contentful (最大内容花了多久)
 - Time to Interactive (何时用户可以交互)
 - Total Blocking Time
 - Cumulatice Layout Shift
 
# 优化提示
- Remove unused JavaScript 移除无用JavaScript
 - Eliminate render-blocking resources 阻塞JS
 
# 性能指标PerformanceAPI
- DNS 解析耗时: domainLookupEnd - domaminLookupStart
 - TCP 链接耗时: connectEnd - connectStart
 - SSL 安全连接耗时: connectEnd - secureConnectionStart
 - 网络请求耗时(TTFB): responseStart - requestStart
 - 数据传输耗时:responseEnd - responseStart
 - DOM 解析耗时:domInteractive - responseEnd
 - 资源加载耗时:loadEnventStart - domContentLoadedEventEnd
 - First Byte时间:responseStart - domainLookupStart
 - 白屏时间:responseEnd - fetchStart
 - 首次可交互时间: domInteractive - fetchStart
 - DOM Ready 时间:domContentLoadEventEnd - fetchStart
 - 页面完全加载时间: loadEventStart - fetchStart
 - http 头部大小: transferSize - encodeBodySize
 - 重定向次数:performance.navigation.redirectCount
 - 重定向耗时:redirectEnd - redirectStart
 
# 性能监测对象 PerformanceObserver
PerformanceObserver 用于监测性能度量事件,在浏览器的性能时间轴记录下一个新的 performance entries 的时候将会被通知 。
function perfObserver(list, observer) {
   // Process the "measure" event
   // 处理 "measure" 事件
}
let observer = new PerformanceObserver(perfObserver);
observer.observe({entryTypes: ["measure"]});
 1
2
3
4
5
6
2
3
4
5
6
# 代码优化
Google JavaScript Style Guide (opens new window)
- node 查看性能
 
const { performance, PerformanceObserver } = require('perf_hooks');
const add = (a,b) => a+b;
const num1 = 1;
const num2 = 2;
performance.mark('start');
for(let i = 0; i < 10000000; i++) {
  add(num1, num2);
}
add(num1, 's');
for(let i = 0; i < 10000000; i++) {
  add(num1, num2);
}
performance.mark('end');
const observer = new PerformanceObserver((list) => {
  console.log(list.getEntries()[0]);
})
observer.observe({ entryTypes: ['measure'] });
performance.measure('测量1', 'start', 'end');
// PerformanceEntry {
//   name: '测量1',
//   entryType: 'measure',
//   startTime: 25.567501,
//   duration: 32.1128
// }
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
去除
const { performance, PerformanceObserver } = require('perf_hooks');
const add = (a,b) => a+b;
const num1 = 1;
const num2 = 2;
performance.mark('start');
for(let i = 0; i < 10000000; i++) {
  add(num1, num2);
}
for(let i = 0; i < 10000000; i++) {
  add(num1, num2);
}
performance.mark('end');
const observer = new PerformanceObserver((list) => {
  console.log(list.getEntries()[0]);
})
observer.observe({ entryTypes: ['measure'] });
performance.measure('测量1', 'start', 'end');
// PerformanceEntry {
//   name: '测量2',
//   entryType: 'measure',
//   startTime: 25.243699,
//   duration: 12.227501
// }
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$ node --trace-opt  perfromance.js
[marking 0x00e92e6c1c61 <JSFunction (sfi = 000001582941F6F9)> for optimized recompilation, reason: hot and stable]
[marking 0x00e92e6cd6d1 <JSFunction add (sfi = 000001582941F7C1)> for optimized recompilation, reason: small function]
[compiling method 0x00e92e6cd6d1 <JSFunction add (sfi = 000001582941F7C1)> using TurboFan]
[compiling method 0x00e92e6c1c61 <JSFunction (sfi = 000001582941F6F9)> using TurboFan OSR]
[optimizing 0x00e92e6c1c61 <JSFunction (sfi = 000001582941F6F9)> - took 0.210, 0.388, 0.035 ms]      
[optimizing 0x00e92e6cd6d1 <JSFunction add (sfi = 000001582941F7C1)> - took 0.577, 0.753, 0.020 ms]  
[completed optimizing 0x00e92e6cd6d1 <JSFunction add (sfi = 000001582941F7C1)>]
[marking 0x00e92e6c1c61 <JSFunction (sfi = 000001582941F6F9)> for optimized recompilation, reason: hot and stable]
[compiling method 0x00e92e6c1c61 <JSFunction (sfi = 000001582941F6F9)> using TurboFan OSR]
[optimizing 0x00e92e6c1c61 <JSFunction (sfi = 000001582941F6F9)> - took 0.193, 0.369, 0.026 ms]      
PerformanceEntry {
  name: '测量2',
  entryType: 'measure',
  startTime: 48.314,
  duration: 20.3714
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 函数优化
- lazy parsing 懒解析 vs eager parsing 解饿解析
 - 为了优化加载速度,浏览器对函数一般采取lazy parsing 懒解析方式(调用时才会解析)。
 - 但是某些情况下需要立即执行该函数,会触发浏览器对函数进行eager parsing 饥饿解析
 - 如何直接进行饥饿解析,看如下代码
 
export default () => {
  const add = (a,b) => a + b;
  const num1 = 1;
  const num2 = 2;
  add(num1,num2);
}
// 给函数+()告诉解析器,要对函数进行饥饿解析
export default () => {
  const add = ((a,b) => a + b);
  const num1 = 1;
  const num2 = 2;
  add(num1,num2);
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 对象优化
- 以相同顺序初始化对象成员,避免隐藏类的调整
 - 实例化后避免添加新的属性
 - 尽量使用Array代替array-like对象
 - 避免读取超过数组的长度
 - 避免元素类型转换
 
# 以相同顺序初始化对象成员,避免隐藏类的调整
/* 1 */ 
// ✔
class RectArea { // HC0
  constructor(l,w) {
    this.l = l; // HC1
    this.w = w; // HC2
  }
}
const rect1 = new RectArea(3,4)
const rect2 = new RectArea(5,6)
// ❌
const car1 = { color: 'red' }; // HC0
car1.seats = 4; // HC1
const car2 = { seats: 2 }; // HC2
car2.color = 'blue'; // HC3
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 实例化后避免添加新的属性
/* 2 */
const car1 = { color: 'red' }; // In-object 属性
car1.seats = 4; // Noramal/Fast 属性, 存储在property store中,需要通过描述数组扫描间接查找
 1
2
3
2
3
# 尽量使用Array代替array-like对象
Array.prototype.forEach.call(arrObj, (value, index) => { //不如真是数组上效率高
  console.log(`${index}:${value}`)
})
const arr = Array.prototype.slice.call(arrObj, 0); // 转换的代价比影响优化小
arr.forEach((value, index) => {
  console.log(`${index}:${value}`)
})
 1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 避免读取超过数组的长度
function foo(array) {
  for(let i = 0; i <= array.length; i++) { // 越界比较
    if(array[i] > 1000) { // 1、造成undefined跟数字比较 2、沿原型链的查找
      console.log(array[i]) // 业务上是无效、出错
    }
  }
}
 1
2
3
4
5
6
7
2
3
4
5
6
7
# 避免元素类型转换
const arr = [1,2,3]; // PACKED_SMI_ELEMENTS  packed 没有undefined  smailInt
arr.push(4.4); // PACKED_DOUBLE_ELEMENTS
 1
2
2

# HTML优化
HTML Best Practices (opens new window)
HTML Living Standard (opens new window)
- 减小iframe使用
 - 压缩空白符(webpack打包去除)
 - 避免深层次的嵌套
 - 避免table布局
 - 删除注释(webpack打包去除)
 - CSS&JavaScript 尽量外链
 - 删除元素默认属性
 
# 字体优化
- font-display