Node端性能
性能评估
-
通过性能测试工具评估:
- :支持lua脚本,可以轻松应对各种测试需求,如
-- 带随机参数请求function request() wrk.headers["Connection"] = "keep-Alive" arg = math.random(1, 500) path = "/random?arg=" .. arg return wrk.format("GET", path)end复制代码
-
通过v8 profiling查看程序执行过程数据,,可以在Webstorm【Run/Debug Configurations】里面配置,注意需要先安装:
常见优化方案
- 并发请求,例如:promise.all并发三方HTTP接口调用、RPC调用
- 如果用到mysql
- 使用数据库连接池,重用连接
- 常用查询建立索引
- 用程序避免联合查询
- 读写分离
- 加入缓存策略
前端性能
DNS查询
- 减少DNS查询次数
TCP/HTTP
优化核心
- 消除和减少不必要的网络延迟
- 把传输字节数降到最少
具体步骤
- 减少HTTP请求:对于HTTP1.0/1.1 减少请求资源数(打包、压缩、合并等)
- 使用CDN
- 添加Expires首部并配置ETag标签
- GZip资源
- 避免HTTP重定向
- 持久化连接:避免TCP的三次握手,HTTP1.1默认开启,HTTP1.0可以使用:Connection: Keep-Alive
- HTTP1 不支持多路复用,可以为一台主机并行打开多个TCP会话(一般为6个)
- 消除不必要的请求字节(HTTP1 请求、响应头不会被压缩)
- 嵌入资源,如:Base64嵌入资源(针对小的静态图片资源)
客户端渲染
关键渲染路径:DOM -> CSSDOM / JS -> RenderTree -> Layout -> Paint
浏览器渲染过程
构建DOM
- 构建过程:character -> token -> node -> DOM
- 增量构建
构建CSSOM(CSS Object Model)
- 构建过程:character、token、node、CSSOM
- 选择器越复杂,匹配用的时间约多
构建RenderTree
- RenderTree包含所有需要呈现在页面上的节点信息
- display: none的元素不会被添加到RenderTree中,因为它不需要被渲染,visibility: hidden的元素会被添加到RenderTree中
Layout
- 计算需要渲染的节点的大小和位置
- 节点位置和大小是基于将viewport计算的
- 在移动端通常将viewport设置为浏览器推荐的理想视口,以保证字体显示大小易于阅读
- 旋转屏幕、修改浏览器窗口大小,修改位置大小相关的CSS属性,都可能触发Layout
Paint
- 根据background、border、box-shadow等样式,将Layout生成的区域填充为最终将显示在屏幕上的像素
资源优化
CSS性能优化(防止资源阻塞初次渲染)
- media query(link里面加上media)
- 此时样式表仍然会加载,当浏览器环境不匹配媒体查询条件时,该样式表不会阻塞渲染
- 针对不同媒体环境拆分CSS文件,避免为了加载非关键CSS资源,而阻塞初次渲染
- 使用DOM API添加link不会阻塞初次渲染
var style = document.createElement('lin');style.rel = 'stylesheet';style.href = 'index.css';document.head.appendChild(style);复制代码
- preload & prefetch & prerender(不止可以用于CSS)
- rel="preload",不是stylesheet不会阻塞渲染
- preload是resource hint规范中定义的一个功能,resource hint告知浏览器提前建立连接或加载资源,以提高资源加载的速度:
- preload:https://www.w3.org/TR/preload/
- prefetch & prerender:https://w3c.github.io/resource-hints/#prefetch
- 浏览器遇到标记为preload的link时,会开始加载它
- 当onload事件发生时,将rel改为stylesheet,即可应用此样式
- 可以通过 loadCSS.js 使用preload (CSS preload polyfill):原理其实就是使用DOM API
复制代码
JS性能优化
- JS会阻塞HTML Parse(HTML解析器,增量),因而会阻塞出现在脚本后面的HTML标记的渲染
- 原因:JS可以通过document.write修改HTML文档流,因此在执行JS时,浏览器会暂停解析DOM的工作
- CSS会阻塞JS
- 浏览器资源加载策略(preload,与前面CSS preload不一样,详见:https://juejin.im/post/5a4ed917f265da3e317df515)
- 当HTML Parser被脚本阻塞时,Parser虽然会停止构建DOM,但仍会识别该脚本后面的资源,并提前加载
- 性能优化(防止阻塞)
- 将资源放到body底部
- 使用defer延迟脚本执行:使用defer,该脚本会被推迟到整个HTML文档解析完后,再开始执行。被defer的脚本,在执行时会严格按照在HTML文档中出现的顺序执行。使用defer方法,可以提早脚本资源加载
- 使用async异步加载脚本:该脚本不会阻塞HTML parser,也不会被CSS阻塞,脚本加载完就开始执行。async适用于无依赖的独立资源(比如百度统计代码)
图片
- 使用blob异步加载
- 使用代替img标签(原理与上面一样),对于图片多的网站轻松提升五倍以上访问速度
字体
- 浏览器为了避免FOUT(Flash Of Unstyled Text),会尽量等待字体加载完成后,再显示应用了该字体的内容。带来了FOIT(Flash Of Invisible Text 问题),导致空白
- 设置多字体,降级方法:使用默认字体
- 异步加载字体文件:通过异步加载CSS,即可避免字体阻塞渲染,还是会空白
其它
- 对于React技术栈,推荐使用
优化关键渲染路径
优化目标
- 关键资源数
- 关键资源体积
- 关键资源网络来回数
勿盲目内联资源
- 若启用HTTP2,则无需内联资源
- 若资源被多个页面共享,则无法充分利用缓存,导致重复得下载
内联与缓存结合
- 首次访问,使用内联,并通过异步(如:rel="prefetch")请求缓存资源,缓存成功通过cookie标记,下次访问时,则只返回外部资源标记
其它
常用工具
性能测试工具
相关资料
补充
TTFB(Time To First Byte):
- 从客户端发出请求到接收到第一个响应字节所花费时间(Transfer-Encoding: chunked)
HTTP2.0主要设计:
- 解决HTTP中“队首阻塞”;
- 二进制分帧机制,无需建立多个TCP连接,从而改进TCP利用率
- 保持HTTP1.1语义
队首阻塞:
- HTTP应用层队首阻塞:按照优先级发送请求
- TCP传输层队首阻塞:TCP要求分组严格按照顺序交付