在移动互联网的时代里,对于一个web站点来说,移动端的用户体验尤为重要。现代web站点的设计和开发都是以移动优先作为第一原则,我们也专门为了移动端的web站点做了相应的优化和提升。而网页的打开速度和页面的流畅度,对于用户是否长时间访问至关重要。我们在移动端的站点通过一系列的方法,最终为了快速打开页面展示网页内容,触达用户,同时能流畅的浏览网页。

\\

移动端的硬件条件,网络条件相对于桌面端,会复杂的多,设备类型多样,硬件配置参差不齐,分辨率碎片化,网络状况在移动过程中稳定性,速率都会变化,而对于一个页面到达用户的终端展示,会经过,用户发起请求,服务端接受请求,服务端处理请求,返回响应内容,在用户终端的浏览器展示内容,用户操作页面发起其他页面时间,而这个过程中任何一个环节的延迟都会造成性能瓶颈,降低用户继续访问的可能性,所以我们在服务器端,浏览器端,网络加载,多个方面做了一系列的优化工作。

\\

WEB服务端优化

\\

有货的WEB端主要使用了nodejs,基于后端服务提供的HTTP接口服务来实现的前后端分离,这里的服务端优化主要是指在nodejs实现的web服务端进行优化。

\\

\\

优化的目的是提升服务端的响应和并发能力,充分发挥nodejs的异步非阻塞的特性,主要从以下几个方面去优化。

\\

接口服务调用的优化

\\

对于一个页面展示的路由,要处理这个路由,可能需要调用多个接口并且进行进行界面逻辑的处理。大体过程:

\\

\\

  • 接口合并 我们对于一个页面调用可以合并的接口,进行接口合并,减少接口调用次数,如:以商品详情页为例,商品的一些特性,可以在一个接口返回,尽可能的减少接口调用的个数,因为每次接口的处理都有网络IO,对象序列化,压缩和解压的过程。\\t
  • 接口异步调用 但是并不是所有的接口都可以合并,对于无法合并的接口,我们尽量使用node的异步非阻塞的特性,进行异步调用,同时调取多个接口,而最终的调用耗时取决于最慢的接口。
    \\t这里要说明一点:对于接口依赖,如A接口依赖B接口的返回结果,像这种情况,我们最好梳理下接口设计,减少这样的串行调用,因为这样,调用耗时是多个接口耗时的总和。\\t
  • 减少接口交互数据 返回的数据较多的情况下,会导致JSON序列化,数据批量对象处理,产生额外的性能损耗。可以做下接口返回数据结构的精简,返回必要的字段(页面会展示用到的数据)以及可以调整返回item个数。从而达到减少数据的返回消息体的大小。此外请求接口时需要gzip压缩,可以大大的减少网络传输的时间,尽管需要解压会消耗一部分CPU的时间,但是对接网络IO的损耗,还是值得的。\

可以分享一组基准压测数据,在调用接口使用gzip和不使用gzip的QPS数据

\\

\\

  • 减少接口调用次数 如何减少接口调用次数呢?对于一个页面,可能就会存在调用必要的接口,在这里我们使用到了缓存机制,对于热数据进行接口缓存,我们使用了一些内存数据库,同时对于一些规格数据可以进行进程级的缓存(如:导航信息,品类信息等)。缓存是有一定原则的:第一,需要容易命中的数据,第二,可以被缓存的数据,数据更新频率是可控的。通过缓存机制,一部分接口调用就会走到缓存,减少的接口调用的IO。此外缓存的数据可以是对接口数据处理后的视图对象,同时也减少的数据处理的时间。\\t
  • 内部服务调用DNS缓存 我们的内部服务使用域名方式,为了提高服务的灵活配置,但是需要内部DNS服务器进行域名解析,这个是有一定耗时的,所以我们在DNS这块加了DNS应用端cache,减少DNS解析的时间。\

业务处理的优化

\\

现在我们主要的服务端业务处理,主要对于页面逻辑的处理,如路由控制,会话处理,视图对象处理,模板渲染。我们在这些处理过程中进行了一些优化。

\\

如何发现node的性能问题,主要可以使用cpu-profile进行cpu处理堆栈的抓取,然后使用chrome的dev-tools进行火焰图的分析,找到性能瓶颈。

\\

  • 计算密集型操作使用原生实现 js是不擅长计算密集型的操作,如Hash处理,加密解密,压缩解压,像这些操作可以直接使用nodejs提供的原生实现(crypto, Zlib)\

以下是一组使用原生和js的md5处理性能对比:

\\

\\

返回结果:

\\

\native md5::31.59\result:5d3b7d53fdd4daaa2d75370e8a5d1789\js md5::181.54\result:5d3b7d53fdd4daaa2d75370e8a5d1789

\\

差距还是比较明显的。

\\

模板渲染的优化

\\

我们在实际使用过程中,发现模板的渲染是十分消耗性能的,特别的模板的预处理过程,如果预处理过程是在用户访问过程中去处理,会慢不止一个数量级,所以我们把预处理的过程提前了(改造了hbs),在启动web应用时,已经预编译完成。同时我们发现handlebars的一些默认配置属性,如缩减处理,在字符串拼接过程中会损耗一定的性能,所以可以关闭html片段的缩减。

\\

此外,我们还把可以缓存的html片段进行进程级的缓存,性能提升显著,可以把一些不怎么会变的html公共部分进行缓存。通过内部缓存刷新机制进行定时刷新html片段。

\\

nginx的优化

\\

启用page cache 使用了nginx的proxy_cache模块,配置了一些缓存机制,不同页面路由的缓存时长会读取node服务在http头里面返回的max-age时间。

\\

\proxy_cache cache_one_wap;\proxy_cache_valid 200 1m;\proxy_cache_min_uses 1;\proxy_cache_key $host$uri$args;\add_header X-Cache-Status $upstream_cache_status;

\\

然后我们会在应用服务添加max-age配置的中间件,对路由进行拦截装饰http header:

\\

\const cachePage = {\    '/': x * MINUTE,\    '/boys': x * MINUTE,\    '/girls': x * MINUTE,\    '/kids': x * MINUTE,\    '/lifestyle': x * MINUTE,\    ...\}

\\

另外要注意一个设置nginx缓存的时候,如果有服务端设置cookies的情况下,并且以服务端cookies的值作为标识用户会话信息,不要设置proxy_ignore_headers \"Set-Cookie\";,不然缓存会导致会话信息窜读的情况。

\\

全站HTTPS

\\

为什么要上全站https呢,这个主要考虑到https可以防止中间人攻击以及内容劫持,提高网站的访问安全性。但是因为多了SSL/TLS的服务端和浏览器端的处理,在性能方面也会有相应的下降,但是我们同时也启用HTTP/2,而主要的特性:多路复用 (Multiplexing)多路复用允许同时通过单一的 HTTP/2 连接发起多重的请求-响应消息。另外PWA里面的service worker 也是必须要求网站的协议是https的,同时也是为了这个做了铺垫,HTTPS是现代WEB的发展趋势。至于PWA不是本文讨论的重点,可以在后续其他的主题展开。

\\

浏览器端优化

\\

移动终端五花八门,导致过重的浏览器的处理和效果,会导致体验的不一致,特别是安卓手机,所以我们在浏览器端的策略是,尽量轻量化网页,当前页面只处理当前必要的内容多页面的方式。这个和现在google提出的开源项目AMP是一个思路。

\\

首屏直出优化

\\

从用户发出请求到页面完全展示,一般来说在网络正常基本上1s以上,但是如果页面打开耗时超过1s,用户流失的概率就会线性上升。所以移动端秒开至关重要,所以我们的思路是减少白屏时间,尽快把浏览器可视区域展示出来,就是所谓的首屏,我们就从以下几个方面做了优化。

\\

直出文档,简化dom结构 服务端进行HTML渲染输出,只处理首屏需要的HTML,并且简化DOM的树状结构,如:

\\

\\u0026lt;div class=\"nav\"\u0026gt;\   \u0026lt;ul\u0026gt;\      \u0026lt;li\u0026gt;xxxx\u0026lt;/li\u0026gt;\      \u0026lt;li\u0026gt;xxxx\u0026lt;/li\u0026gt;\   \u0026lt;/ul\u0026gt;\\u0026lt;/div\u0026gt;

\\

可以简化成

\\

\   \u0026lt;ul class=\"nav\"\u0026gt;\      \u0026lt;li\u0026gt;xxxx\u0026lt;/li\u0026gt;\      \u0026lt;li\u0026gt;xxxx\u0026lt;/li\u0026gt;\   \u0026lt;/ul\u0026gt;

\\

在页面只保留必要的DOM,此外,可以估算下世面手机分辨率,确定最大首屏的输出可视区域的DOM,如果需要滚屏到第二屏的,可以延迟通过Ajax获取内容加载。减少DOM,可以减少HTML的输出,当然更重要的浏览器的布局和渲染的时间大大减少。当然首屏的静态资源和样式要优先加载,下个关键点就是首屏只加载所需样式和静态资源。

\\

首屏只加载所需样式和静态资源 光有DOM的处理是远远不够的,要从白屏到展示完整的首屏,还需要样式和静态资源。所以要优先加载样式和静态资源,所以直接把公共样式中首屏用到的样式抽离出来,并且首屏用到的样式,直接在html页面内置。此外,图片和字体等其他需要展示的部分,优先加载,促使首页快速展示出来。

\\

首屏渲染,js延迟执行

\\

当首屏渲染的时候,这时候js的执行可能会阻塞渲染的线程,所以为了减少对浏览器主线程的渲染过程,尽量延迟进行js执行,特别是操作DOM的情况,不然首屏展示过程中会产生额外的重布局和重绘,js引入或代码直接放到页面的底部,在body之后,在html之前。

\\

优化直出服务端处理时间 另外再强调下直出的关键,服务端的处理wait尽量减少,对于首屏直出至关重要。

\\

图片优化

\\

图片质量和体积控制 对于移动终端来说,分辨率相当于桌面会小很多,首先会降低图片的分辨率,以及图片的DPI值,第二步会降低图片的质量,以保证图片的体积变小。

\\

提高CDN缓存命中,第一,减少缩略图的尺寸规格,第二,尽量和其他端的图片规格保持一致,如APP端,小程序。

\\

WEBP的运用 webp不是所有的浏览器都支持,所以,我们的做法是对于需要js加载的图片,进行webp的判断,如果支持,就是直接加载webp的格式图片,如果不支持,采用默认的jpg的格式。

\\

\if (window.supportWebp \u0026amp;\u0026amp; (/format\\/png/i.test(query) || /format\\/jpg/i.test(query))) {\    imgUrl = imgUrl.replace(/format\\/png/i, 'format/webp').replace(/format\\/jpg/i, 'format/webp');\}

\\

\\

浏览器端缓存优化

\\

当存在缓存,可以减少浏览器的再次请求,大大提升了网页的打开速度,一个优秀的缓存策略可以缩短网页请求资源的距离,减少延迟,并且由于缓存文件可以重复利用,还可以减少带宽,降低网络负荷。那么下面我们就来看看服务器端缓存的原理。

\\

**缓存优化(max-age) **

\\

页面的缓存状态是由http协议的header决定的,我们主要使用了max-age(单位S),设置缓存的最长有效时间,使用的是时间长短,例如说我设置max-age=60,也就是说在请求发出后的60秒内,浏览器再次请求时不会再请求服务器,而是从浏览器缓存中读取数据。

\\

预加载和懒加载

\\

预加载和懒加载是一对好兄弟,用的好,可以极高提升浏览器端的体验,就是要确定在何时预加载,何时懒加载。我们主要在浏览器首屏结束后,当浏览器相对idle的时候,可以预加载下一屏即将展示的内容。

\\

当用户在即将触发下一屏时,下一屏的数据或DOM已经stay by了,自然体验会流畅很多,但是在预加载是需要一个度,因为一个页面的DOM过多,对于浏览器占有的内存也会过多,预加载最好是用户即将触发需要浏览的内容,如第二屏,轮播后面的内容,tab页等。

\\

懒加载的运用场景主要还是为了减少单次DOM渲染的大小,对于当前页面的非可视区域,当需要展示或用户事件触发才进行加载。所以懒加载和预加载,在不同的场景下会有不同的运用,前提是保障页面的流畅度。

\\

DNS预读取

\\

DNS预读取配置的DNS的解析,可以减少DNS的次数,也可以加速不同域名的资源加载,目前支持的浏览器还是比较多的。

\\

配置也很简单:

\\

\\u0026lt;link rel=\"dns-prefetch\" href=\"//cdn.yoho.cn\"\u0026gt;\\u0026lt;link rel=\"dns-prefetch\" href=\"//static.yohobuy.com\"\u0026gt;\\u0026lt;link rel=\"dns-prefetch\" href=\"//img10.static.yhbimg.com\"\u0026gt;\\u0026lt;link rel=\"dns-prefetch\" href=\"//img11.static.yhbimg.com\"\u0026gt;\\u0026lt;link rel=\"dns-prefetch\" href=\"//img12.static.yhbimg.com\"\u0026gt;\\u0026lt;link rel=\"dns-prefetch\" href=\"//img13.static.yhbimg.com\"\u0026gt;\\u0026lt;link rel=\"dns-prefetch\" href=\"//analytics.m.yohobuy.com\"\u0026gt;\\u0026lt;link rel=\"dns-prefetch\" href=\"//search.m.yohobuy.com\"\u0026gt;\\u0026lt;link rel=\"dns-prefetch\" href=\"//list.m.yohobuy.com\"\u0026gt;\\u0026lt;link rel=\"dns-prefetch\" href=\"//guang.m.yohobuy.com\"\u0026gt;

\\

当然最好的减少DNS的时间是减少站点使用DNS的数量,我们会去掉部分二级域名。

\\

CSS,JS的优化

\\

项目构建主要采用了webpack的工具链,对css,进行依赖管理和构建打包,最小化css,js,并针对我们现有的多页面项目进行多入口的分包管理。

\\

多页面css和js构建

\\

打包代码如下,便利js的源文件目录,构建各个页面模块的js,所有的页面会包含两个js文件,libjs(全局公用的js),xxx.js(当前页面特有的js),css也是一样。这样每个页面的js和css都会最小化,同时我们也对这些个静态字符串文件进行gzip压缩,当然这些文件会按照版本进行静态存储,以及CDN的缓存。

\\

\   // 构建各模块子页面JS\    // 新的生成规则 module/page/index.js\    shelljs.ls(path.join(__dirname, '../js/**/index.js')).forEach((f) =\u0026gt; {\        const dir = _.slice(f.split('/'), -3); \        // Important\        // 生成规则:module.page: './js/module/page/index.js'\        entries[`${dir[0]}.${dir[1]}`] = path.join(__dirname, `../js/${dir.join('/')}`);\    });

\\

DOM优化

\\

页面流畅度和DOM渲染和操作息息相关,渲染流程大致如下:

\\

  • 处理HTML 标记并构建 DOM 树。\\t
  • 处理 CSS 标记并构建 CSSOM 树。\\t
  • 将 DOM 与 CSSOM 合并成一个渲染树。\\t
  • 根据渲染树来布局,以计算每个节点的几何信息。\\t
  • 将各个节点绘制到屏幕上。\

\\

可以使用DEVTOOLS分析整个渲染过程中那块存在性能问题。

\\

\\

简化DOM,DOM操作优化

\\

简化DOM可以减少渲染过程的时间,优化DOM操作,可以减少重布局和重绘的时间。简化DOM在上面的首屏直出已经介绍过相应的做法。

\\

这里主要说下DOM操作的优化,第一,减少DOM操作次数,可以把多次DOM操作在js的执行过程中生成好结果HTML,一次插入到DOM;第二,尽量在使用不在页面DOM树里面直接操作,可以脱离文档流的DOM中进行操作,可以使用fragment,一次插入文档流中。

\\

当然现在的react和vue都使用虚拟DOM的技术,通过diff算法进行通用化的DOM操作。这个也不失是一种效率高效的做法,但是对于一些不易优化的页面,还是需要人为干预和操作DOM使其性能最好。

\\

减少重布局和重绘

\\

第一,要减少布局调整,当您更改样式时,浏览器会检查任何更改是否需要计算布局,以及是否需要更新渲染树。对“几何属性”(如宽度、高度、左侧或顶部)的更改都需要布局计算。第二,绘制的复杂度、减小绘制区域:除 transform 或 opacity 属性之外,更改任何属性始终都会触发绘制。绘制通常是像素管道中开销最大的部分;应尽可能避免绘制。

\\

通过层的提升和动画的编排来减少绘制区域。可以使用 Chrome DevTools 来快速确定正在绘制的区域。打开 DevTools,按下键盘上的 Esc 键。在出现的面板中,转到“rendering”标签,然后选中“Show paint rectangles”。每次发生绘制时,Chrome 将让屏幕闪烁绿色。如果看到整个屏幕闪烁绿色,或看到你认为不应绘制的屏幕区域,则应当进一步研究。

\\

\\

页面动画优化

\\

尽量使用CSS3的动画,使用 transform 和 opacity 属性更改来实现动画。使用 will-change 或 translateZ 提升移动的元素。避免过度使用提升规则;各层都需要内存和管理开销。此外,需要减少动画的图层,每多一个图层,会多一份内存占有和管理的开销。

\\

如果一定要使用js的动画,建议使用:requestAnimationFrame。此外,能不用页面动画的场景尽量不要使用动画,如果一定要使用,可以简化动画渲染的过程。

\\

之前我们使用过一个js插件,iScroll就是一个案例,页面内初始化了多个iScroll实例,特别在安卓手机上特别卡顿,最后,我们的解决办法是自己使用css3动画和touch事件简单轻量的实现需要滑动的部分,对于页面滚动部分使用了原生的scroll,保证了不同终端体验一致。

\\

总结

\\

移动web端的优化以上每个点如果展开去讲,都可以单独写一篇文章,我们分别在以上方面做了优化,并且,也产生了比较不错的效果,移动端的打开速度和体验都有了不错的提升,普遍打开的时间提升了30-50%,在网络稳定的情况下,基本上服务端的耗时在50ms以内,首屏时间在500ms以内,但是优化这件事情是永无止境的,没有最好,只有更好,需要开发者探究根本勇于创新,达到更好的更优的境地。

\\

我们后续,还可以在web的基本技术点上深挖,同时在PWA以及AMP等现代web新思维的多个方面大家积极面对,继续探索,在未来的web前端之路可以走的更好,提供更优的用户体验,创造更高社会价值。

\\

感谢徐川对本文的审校。

有货移动Web端性能优化探索实践相关推荐

  1. 高性能网站建设进阶指南:Web开发者性能优化最佳实践 pdf扫描版

    高性能网站建设进阶指南:Web开发者性能优化最佳实践是<高性能网站建设指南>姊妹篇.作者Steve Souders是Google Web性能布道者和Yahoo!前首席性能工程师.在本书中, ...

  2. Flutter Web 在《一起漫部》的性能优化探索与实践

    一起漫部 是基于区块链技术创造的新型数字生活. 目录 前言 开发环境 渲染模式 首屏白屏 优化方案 启屏页优化 包体积优化 去除无用的icon 裁剪字体文件 deferred延迟加载 启用gzip压缩 ...

  3. 维护几十种语言和站点,爱奇艺国际站WEB端网页优化实践

    1.前言 爱奇艺国际站(www.iq.com)提供了优质的视频给海外各国用户,自上线以来,现已支持几十个国际站点,并且在东南亚多个国家保证了海量用户高速观看体验. 国际站业务的特点是用户在境外访问,后 ...

  4. 深度讲解:web前端性能优化

    一.课程简介: 1.课程大纲 涉及到的分类 网络层面 构建层面 浏览器渲染层面 服务端层面 涉及到的功能点 资源的合并与压缩 图片编解码原理和类型选择 浏览器渲染机制 懒加载预加载 浏览器存储 缓存机 ...

  5. 大型网站技术架构(3):WEB 前端性能优化

    上次说到了性能优化策略,根据网站的分层架构,可以大致的分为 web 前端性能优化,应用服务器性能优化,存储服务器性能优化三大类 这次来说一下 web 前端性能优化,一般来说,web 前端就是应用服务器 ...

  6. web前端性能优化总结

    概括 涉及到的分类 网络层面 构建层面 浏览器渲染层面 服务端层面 涉及到的功能点 资源的合并与压缩 图片编解码原理和类型选择 浏览器渲染机制 懒加载预加载 浏览器存储 缓存机制 PWA Vue-SS ...

  7. web页面性能优化及SEO优化

    web页面性能优化 前言: 在同样的网络环境下,两个同样能满足你的需求的网站,一个"Duang"的一下就加载出来了,一个纠结了半天才出来,你会选择哪个?研究表明:用户最满意的打开网 ...

  8. Web前端性能优化思路

    本文旨在整理常见Web前端性能优化的思路,可供前端开发参考.因为力求精简,限于篇幅,所以并未详述具体实施方案. 基于现代Web前端框架的应用,其原理是通过浏览器向服务器发送网络请求,获取必要的inde ...

  9. web常见性能优化总结(浏览器渲染过程详解)

    文章目录 一.什么是web的性能优化 二.web性能优化的目的 三.web性能优化的原理 3.1 加载文档 3.2 生成dom树 3.3 加载css 和js 3.4 生成CSS OM 3.5 rend ...

最新文章

  1. oracle 无效索引
  2. node 获取表单数据 为空_Java实现数据结构之【链表】
  3. 如何实现一个优质的微服务框架:Apache ServiceComb 的开放性设计
  4. java数据库视图工具_数据库视图工具类
  5. pythonfor循环100次_以写代学: python for循环 range函数 xrange函数
  6. 前端渲染引擎doT.js解析
  7. php 精度运算,PHP BC 库(任意精度数字运算) | 网游世界
  8. 1.7 什么时候该改变开发_测试集和指标
  9. tcp服务器测试网页版,tcp测试服务器
  10. u盘重置后计算机不显示了,u盘在电脑上不显示了如何恢复
  11. Flutter报setState() or markNeedsBuild() called during build.错误解决办法
  12. 转载:Java导出数据到Excel
  13. halcon多模板匹配,每种模板匹配结果不同颜色轮廓
  14. 阿里设计师带你探讨UxD设计是什么?
  15. jenkins自动化部署
  16. 在github上部署静态页面
  17. 阅读《SentiLARE: Sentiment-Aware Language Representation Learning with Linguistic Knowledge》
  18. Excel 2007中日历控件使用
  19. 电网操作:线路、主变、母线异常讲解及其处理
  20. 把仙剑奇侠传5的音乐从pkg里请出来变成mp3吧

热门文章

  1. 高清动漫视频-动漫专题-好看动画电影-新动漫岛网站制作历程
  2. 揭秘!旅行青蛙背后的真相!
  3. 带你认识路由器:路由器的两个平面和三张表
  4. Vue 新手学习笔记:vue-element-admin 之入门开发教程(v4.0.0 之前)
  5. 物联卡中心:电信物联卡官网,电信物联卡资费标准
  6. 论中国的软件,360和火绒那个更流氓
  7. launchctl mysql_Mac 下利用 Launchctl 自启动 mysql
  8. OUC 软件工程第04组 Alpha冲刺(3/3)
  9. ArcGIS中密度分析详解
  10. 排序算法 Sorting Algorithm(一)