提升现代web app的中的页面性能

前言,本文翻译自https://docs.google.com/presentation/d/1hBIb0CshY9DlM1fkxSLXVSW3Srg3CxaxAbdocI67NCQ/edit#slide=id.g32e52b1ea6_1_0看到之后感觉讲解的系统清晰明了,实属一篇好文。就加上自己的理解翻译了一下,聊以加深印象。

硬件、网络,对性能的而言始终不能避开的两个物理因素

一、 硬件如何影响性能

硬件(即处理能力)决定了计算密集型任务的表现

浏览器必须解析、编译并执行所有的js,如下如所示:



对于每个阶段而言,代码量的差异显然会影响其变现即影响性能,这种差异在低处理能力的机器上的体现尤为明显。

当然其他类型的资源请求也会影响性能,相比之下js的影响是比较突出的。

所以考虑不同用户cpu的状况,减少js怪物(即缩小js体积)是很必要的。可以从以下几方面着手:

  1. 删除不必要js
  2. 延迟加载非关键js
  3. 借助相关工具

1.1 删除不必要js

只在必要的时候进行转换

仅仅对需要ES5的客户端才进行转换,80%的浏览器已经支持ES2015。(结合自己实际开发情况,移动端而言确实80%+的手机已经支持ES2015,仅仅只遇到oppop,vivio这两中手机不支持。)因为转换之后的代价还是有的,如下所示:

//ES2015
books.map(b => b.title);
//ES5
books.map(function(b) { return b.title; }, this);
//体积大了一倍

使用压缩工具/优化工具

像UglifyJS & Closure Compiler 之类的工具,在压缩之外还有一些优化功能。

对大多数的js而言压缩代码中空格移除和符号修改占了95%的工作量,并非是精心的代码转换。

压缩不应该是盲目的,应该平衡下面几点。

  • 更好的压缩比
  • 高额的计算机资源消耗
  • 前期准备
  • 可能的副作用

    压缩可能不是一味的追求体积更小,相对而言,压缩也应该权衡一下其他方面。比较常见就是代码压缩时相比于其他流程,超长的时间消耗。压缩之后可能遇到关键字的问题。

    如何解决其实应该是从本身项目出发。
  • 尽可能的优化可缓存的静态资源
  • 在压缩体积和时间之间找到一个平衡点

使用tree-shaking移除没用的代码

和压缩代码的目的一致,减小资源大小,不过是从另一个层面的解决方案。像webpack,rollup都提供了该功能。

tree-shaking会将没有被用到的exports移除

//tool
//used
export function a(){
console.log('1')
}
export function b(){
console.log('2')
}
//app.js
import {a} from './tool'
a()

function b 未被使用,最终的打包文件中b将会被删除。

ES2015的模块是静态的,可以使用tree-shaking

import/export 在执行之前就被确定,并且两者只能在顶层,没有条件逻辑的情况下使用(毕竟未执行)

tree-shaking的局限

  • 仅仅删除未被使用的导出
  • 不支持所有的代码库(仅仅ES2015)
  • 可能做不到极致

    难以确定删除是否会有副作用,这种打包器只能保留

自我排查

工具不能做到尽善尽美,并且在执行之前确定某项问题是困难的。

当前来说应该从代码规范和代码注释来自我完善。

对于框架

如果非必须,请不要使用。大的框架至少300kb的体积。

当然必要,请基于下面几点来选择:

  • 服务端渲染
  • 懒加载
  • 代码优化
  • 性能

1.2 延迟加载非必需js

先看一下js不同引入方式的差别

默认方式 Async Defer
阻塞渲染
执行时机 加载完成 加载完成 document解析完成

使用代码分割和懒加载

  • 减少启动时需要加载的js
  • 尽可能少的加载不相关的js

    传统的做法是加载Bundle js,代码分割是将代码分成不同的chunk

    这里同样有两种极端:
  • 每个模块对应一个js

    不好压缩

    利于缓存

    粒度更小
  • 整个应用只对应一个js

    便于压缩

    不利于缓存

    粒度太大,即可维护性

    忽然有种中庸的感觉了,凡事皆有度,所有单一操作都不能过分苛求极致,兼顾才是合理

1.3 使用其他工具

使用html和css

某些状况下可能需要vanilla JS(即原生js),框架带来便利的同时不可避免的有其他的一些性能消耗。提到这里有一篇文章大家可以看一下我是怎么把我的 React 应用换成 VanillaJS 的(这是不是一个坏主意)

举个例子:

Netflix 降低了他们登录页50%的TTI(传输时间间隔)通过下面的方式:

  • 使用原生js来代替React
  • 当用户登录的时候加载余下的部分

使用server

将代价昂贵的库放到server端,使用ssr来代替client-side-render.

ssr可以将我们初始页面加载事件减少到原来的1/5并减少不同浏览器之间的差异。

ssr确实首屏的优化确实很大,优点不多说。但这里提一句,不要盲目ssr,特别是初次请求响应时间较长的接口

二、网络的影响

首先了解两个概念:

  • 带宽: 数据吞吐量(比特/秒)
  • 延迟: 延迟数据传输时间(ms)

对于大部分市场来说,带宽是可以满足需求的(这里统计是国外的,平均26兆,国内略低一点),平均页面大小3.5Mb。传输时间(3.5/26)0.13s。国内会差一点。

延迟对性能影响比较明显。

移动网络的延迟

网络 延迟ms
5G <=4
4G <=100
3G 100-500
3G 300-1000

适应移动网络的限制

应该从下面几方面来分别考虑。

  • 减少请求数量
  • 优化关键路径
  • 减少请求大小

2.1 减少请求数量

新建一次连接的代价是昂贵的,要重复以下过程

建立连接需要1至3+响应在数据相应之前。

  1. DNS 查询(可能)
  2. TLS 握手(可能)
  3. 请求资源

初始状态连接不能被充分利用

TCP slow-start限制了在初始响应里里数据被发送的数量

发送更多的数据通常情况下比新建连接要划算。

请求的体积与相应时间并不是线性关系。

两次50k的请求消耗比一次100k的大了不少。

减少重定向的使用

  • 重定向增加了服务器昂贵的循环
  • server-side 相对于client-side来说重定向优秀一点(快并且可缓存)
  • 看一下301和302的响应code

使用缓存

理想状态下,确实资源是否最新不应该通过网络请求

可以通过下面的方式:

  • 使用Content-addressed URLs:

    即内容与地址对应,log13234d.jpg而非log.jpg
  • 使用max-age

这种浏览器调整为Facebook节省了60%的请求

使用service workers来增强缓存

service worker可以帮组我们:

  • 拦截网络请求
  • 访问浏览器缓存
  • 代替发送网络请求来处理过期的资源

使用http2

使用HTTP2时,每个来源只需要一个连接,减少了连接创建的开销。

2.2 优化关键路径

优化页面渲染或者加载时所需的事件以便尽可能的加快完成。

浏览器优化资源请求

对于所有的请求,浏览器对其是有权重处理的,即分不同的优先级来加载。具体来说就是重要会阻塞渲染的优先级比较高。

如下图所示:

使用资源提示

通过以下方式,提前加载或者请求将要用到的内容:

  • Dns-prefresh
  • preconnect
  • Preload(当前页面)
  • Prefetch(下个页面)

2.3 降低请求大小

  • 使用Brotli压缩

    相对于gzip

    更好的压缩比,文件越大越明显

    更快的解压缩

    压缩速度极大提升
  • 减少js体积
  • 优化图片

    23就不再多提了,方式有很多。

结束语

对于好的资源,多读收益还是很明显的。这次翻译感觉体会又多了一些,不过由于本人才疏学浅,如有错误还望多多指正。一言概之,共同学习。更多请移步

提升现代web app中页面性能的更多相关文章

  1. memcache 与 redis 为web app 带来的性能提升

    memcache 与 redis 为web app 带来的性能提升 参考: 1. http://www.cnblogs.com/ToDoToTry/p/3513688.html

  2. 移动web app 中的meta 标签

    <meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scal ...

  3. 从几篇文字得到关于web app开发的性能问题的答案

    1. http://blogs.adobe.com/creativecloud/are-mobile-web-apps-slow/ 2. http://software.intel.com/zh-cn ...

  4. Web App中的Flexbox应用

    虽然语法可能比较混杂,但 Flexbox 还是名不虚传的.它创造的是可伸缩的.有弹性的.可改变视觉顺序的智能盒子.它提供了简单的CSS布局方案范例让容器总是处于垂直水平居中的位置.使用盒模型来工作是非 ...

  5. app中页面滑动,防止a链接误触

    问题 app中list列表,当我们用手滑动屏幕,屏幕上页面内容会快速滚动,不会因为手已经离开了屏幕而滚动停止,突然手触摸暂停,当手指是在a标签上面时,会跳转链接,这对客户体验及其不好 思路 先判断滚动 ...

  6. Java web开发中页面跳转小技巧——跳转后新页面在新窗口打开

    最近学习Java web,在学习过程中想实现一个需求,就是在jsp页面跳转的时候,希望跳转后的新页面在新窗口中打开, 而不是覆盖原来的页面,这个需求使我困惑了好长时间,后来通过大海捞针似的在网上寻找方 ...

  7. HBuilder开发MUI web app溢出页面上下无法滚动问题

    因为没有对页面初始化,所以页面溢出部分不会显示,要解决此问题需要加上下面代码: JS代码: (function($){$(".mui-scroll-wrapper").scroll ...

  8. 怎样禁止手机app 中页面有时候会把数字当做电话号码,从而自动进行打电话功能

    想要禁止这种功能,只需要给头不加一个meta标签就可以了, <meta name="format-detection" content="telephone=no& ...

  9. 【译文】采用chrome的DevTool中TimeLine和profile工具提升Web app性能

    ->译文,原文在这里<- 本文地址: http://www.cnblogs.com/blackmanba/p/web-perfomance-with-Chrome-DevTools.htm ...

随机推荐

  1. [译]百里挑一:21个优质Swift开源App

    Mybridge AI根据代码质量和start排名从900多个开源项目中选出21个开源项目. 1:Firefox iOS [Official] Firefox iOS app built in Swi ...

  2. 求解n皇后

    要求:在国际象棋上摆放n个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上,问有多少种摆法 思路:很直观的想法就是在棋盘上一个一个皇后的摆,如果冲突,则摆放在另一个位置,直至 ...

  3. JAVA中IO流总结

    本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/42119261 我想你对JAVA的IO流有所了解,平时使用的 ...

  4. 中国梦&nbsp;&nbsp;每个农大人的梦

    历经百年风霜,苦经岁月沧桑.农大,一个中原沃土上生长起来的大树,它在用它那不倒的生命力展示着农大的顽强与坚持,而这份苍劲和顽强,却来自于每个农大人,来自于他们的梦想,来自于他们的坚持,来自于他们的努力 ...

  5. 关于Android自定义view 你所需要知道的基本函数

    开始时之前想吐槽一句..iphone的闹钟,12小时制.我成功的把闹钟订到了下午5:00 导致错过一班飞机.心疼改签费. 候机ing,没有事做,来写一下学习自定义view必须掌握的基本函数.这里只挑一 ...

  6. 用boost::bind构造boost::coroutine

    class TestCoro { ... typedef boost::coroutines::coroutione<void ()> Coro; void CoroFun(Coro::c ...

  7. 【Android 应用开发】Android UI 设计之 TextView EditText 组件属性方法最详细解析

    . 作者 :万境绝尘  转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/18964835 . TextView 相关类的继承结构 ...

  8. SpriteBuilder中pivot关节中的Collide bodies属性

    在SpriteBuilder中,pivot类型的关节表示两个物体围绕一个中心旋转运动的关节,也称之为pin关节. 默认情况下Collide bodies是不选的.因为在大多数情况下你不希望pivot连 ...

  9. FFMPEG结构体分析:AVFormatContext

    注:写了一系列的结构体的分析的文章,在这里列一个列表: FFMPEG结构体分析:AVFrameFFMPEG结构体分析:AVFormatContextFFMPEG结构体分析:AVCodecContext ...

  10. g++和gcc的相同点和区别

    gcc和g++的区别和联系 gcc和g++都是GNU(一个组织)的编译器. 1.对于.c后缀的文件,gcc把它当做是C程序:g++当做是C++程序: 2.对于.cpp后缀的文件,gcc和g++都会当做 ...