背景

项目:移动端H5电商项目

痛点:慢!!!

初始方案:最基本的图片懒加载,静态资源放到cdn,predns等等已经都做了。但是还是慢,慢在哪?

显而易见的原因:由于前后端分离,所有的数据都由接口下发,之后根据模板渲染页面。也就是说,我们需要先加载js,等到js加载完毕之后,请求接口,接口返回数据之后,渲染页面,加载图片等等。尽管使用了模块化的加载方式,但是对于要求高的首页和活动页,给用户的感知也不是很好。

初版解决方案

最初,由于时间紧迫,基本上都是从客户端作优化处理,基本上可以总结为以下几个方面。

一、本地缓存

我们做了本地缓存优化的策略,第一次请求之后就把接口数据缓存到localStorage里面,并且存储当时的时间,设定过期时间,一般设置为5分钟,用户在5分钟内重复打开页面,不会再次请求接口,从localstorage中拿取数据,直接渲染页面。

后续干脆把模板渲染好的html片段存储了起来,直接拼接,省去了模板计算的时间。

基本实现方案如下:

var
cache = localStorage.getItem('cache')
, expires = 5 * 60 * 1000
; // 判断是否过期
function isOverdue(pastTime, expires) {
return Date.now() - pasttime >= expires;
} if (cache && !isOverdue(cache.time, expires)) {
// 说明缓存存在,并且没有过期
// 就正常取cache.data做相应的渲染
} else {
// 说明缓存不存在或者已经过期了
// 重新请求接口
$.get('a.cn', funciton (res) {
// do something
// 把对应的渲染操作处理完成之后,将数据缓存,并记录当前的时间
localStorage.setItem('cache', {
data: res,
time: Date.now()
})
})
}

然而还是不够,新用户在首次打开时,还是不能秒开页面,并且用户在5分钟之后重新加载之时,仍然会有一定的延迟(由于浏览器会缓存一部分静态资源,此时再打开并不会像用户初次打开一样那么慢)。

二、进一步缓存静态资源

在日常开发中,有很多依赖库,常用的fastclick,swipe等等,这些库,没有必要每次都去加载,虽然浏览器会对一些静态资源做缓存,但是却不能完全被我们控制,所以,可以将这些不常发生变化的静态资源缓存起来,同样的,存到localStorage里面。

需要注意

这个方案有一个问题,如果是直接加载的script标签,是无法直接拿到它的脚本内容的。

<script id="script1" src="js/jquery.js"></script>
console.log(document.querySelector('#script1').innerHTML);
// 此时输出的是undefined,因为innerHTML是获取标签内容,此时script标签里并没有内容。
<script id="script2">
console.log('2');
</script>
console.log(document.querySelector('#script2').innerHTML);
// 此时输出的是console.log('2');
// 因为innerHTML是获取标签内容,此时script标签里并没有内容。

这当然不是我们想要的,我们需要的是外链js的可执行代码。

动态添加js的两种方案

我在前一篇高性能JavaScript读书笔记中提到了两种方案。

1. 动态脚本元素

var script = document.createElement('script');
script.type = 'text/javascript';
script.onload = function () {
// do something
}
script.src = 'jquery.js';
document.getElementByTagName('heda')[0].appendChild(script);

这种方法可以监控到脚本的完成事件,但是由于也是通过添加一个script标签,并不能拿到我们想要的js代码。

2. 通过XMLHttPRequest脚本注入

var xhr = new XMLHttpRequest();
xhr.open("get", "file1.js", true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
localStorage.setItem('file1', xhr.responseText);
}
}
}

需要特别注意的是,这个方法有跨域的风险,所以,我们需要静态资源服务器的allow-origin设置为*。或者直接加载本域名下的js。

有同学要问了,既然localStorage这么强大,为什么不把所有的东西都缓存起来呢?

当然是因为它的大小有限制,在FireFox和chrome中,一般来说,sessionStorage和localStorage大小为10MB,而safari只有5MB。详见这篇文章

这就限制了我们什么都存的想法。如果图片较小,可以缓存起来。

第二版解决方案

在前一版方案里,我们解决了后续加载的速度缓慢问题,在后续的页面打开速度上,基本上可以做到秒开。

但是这个方案还是有不足,对于新用户的体验不是很好,如果用户在5min的这个时间点上打开,速度还是会有所下降。

最后还是只能做SSR。

知乎上有一个问题,为什么现在又流行服务端渲染html?

服务端渲染有很多好处,对我们此时而言,最大的好处就是页面直出。省去了请求接口这一步操作。并且对于提高用户体验上来说,很有好处。

如果时间充裕,可以使用node做服务端,但是由于历史原因,我们这个项目迁移起来也比较费时间,所以最后决定使用openresty来做。

openResty的教程网上很多了,我也不多说,除了官方git,推荐开涛博客学习。

不论我们是在客户端取接口数据,还是服务端,活动页的数据一般来说都有一定持续时长,也就是说,我们也可以在我们的nginx服务器上做一个缓存,假设有一个用户访问了一个活动,那么在接下来的五分钟之内,其他任何用户(相同权限下)访问到的就是第一个用户访问时缓存好的页面。

local args = ngx.req.get_uri_args()
local acId = args['acId']
local key = 'ac' .. acId
local expire = 5 * 60 --缓存时间5分钟 local value = dict.getData(key, expire) if not value then
local res = ngx.location.capture('/a.json') if res.status == 200 then
-- dict是一个用来处理存储和读取逻辑的脚本
dict.setData(key, res.body)
else
ngx.say(dict.getData(key))
end
else
-- ngx.log(4, type(value))
ngx.say(value)
end

在dict中,我们可以把接口数据转换成通过模板转换为html片段存储起来。这样,用户在第一次进入我们的页面以后,也不会感觉慢了。

what's more

openResty能做的事不仅仅是这些,一些网关上权限的控制等等都可以用它来实现。

上面两个方案还有一些不足之处,比如首屏可能内容比较多,一次都加载过来,不一定会快。直观的首屏的由服务端渲染,对于不重要的内容,可以通过AJAX来异步加载。

如何计算活动页这样的页面中,首屏有多大,如何组织代码,哪些部分采用服务端渲染,哪些采用AJAX。这些问题在实际开发中也需要考虑。

限于时间,此次没有能比较完善的解决这个问题,在日后开发中,还会继续完善活动页优化方案。

移动端H5活动页优化方案的更多相关文章

  1. [转] 钉钉的H5性能优化方案

    对于一个H5的产品,功能无疑很重要,但是性能同样是用户体验中不可或缺的一环.原本H5的渲染性能就不及native的app,如果不把性能优化做起来,将极大地影响用户使用产品的积极性. 用户感受 当用户能 ...

  2. H5性能优化报告以及方案模板

    H5性能优化方案: 链接:https://pan.baidu.com/s/1LCT83dJMmkvXabne3aWnzw 提取码:dc5z H5性能优化报告: 链接:https://pan.baidu ...

  3. 移动端H5页面高清多屏适配方案

    背景 开发移动端H5页面 面对不同分辨率的手机 面对不同屏幕尺寸的手机 视觉稿 在前端开发之前,视觉MM会给我们一个psd文件,称之为视觉稿. 对于移动端开发而言,为了做到页面高清的效果,视觉稿的规范 ...

  4. 解惑好文:移动端H5页面高清多屏适配方案 (转)

    转自:http://mobile.51cto.com/web-484304.htm https://github.com/amfe/lib-flexible/blob/master/src/makeg ...

  5. [转]:移动端H5页面高清多屏适配方案

    原文链接:http://www.tuicool.com/articles/YJviea 背景 开发移动端H5页面 面对不同分辨率的手机 面对不同屏幕尺寸的手机 视觉稿 在前端开发之前,视觉MM会给我们 ...

  6. 移动端H5地图离线瓦片方案(1)(2)

    2在作者另一篇 移动端H5地图离线瓦片方案   文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 移动端的网速和 ...

  7. vue移动端h5页面根据屏幕适配的四种方案

    最近做了两个关于h5页面对接公众号的项目,不得不提打开微信浏览器内置地图导航的功能确实有点恶心.下次想起来了的话,进行总结分享一下如何处理.在vue移动端h5页面当中,其中适配是经常会遇到的问题,这块 ...

  8. 解惑好文:移动端H5页面高清多屏适配方案

    背景 开发移动端H5页面 面对不同分辨率的手机 面对不同屏幕尺寸的手机 视觉稿 在前端开发之前,视觉MM会给我们一个psd文件,称之为视觉稿. 对于移动端开发而言,为了做到页面高清的效果,视觉稿的规范 ...

  9. 移动端H5优化

    H5前端优化收藏的网址: https://zhuanlan.zhihu.com/p/25176904 http://tgideas.qq.com/webplat/info/news_version3/ ...

随机推荐

  1. 【noip模拟】Fantasia

    Time Litmit: 1000ms      Memory Limit: 256MB Description 给定一张 $N$ 个点.$M$ 条边的无向图 $G$ .每个点有个权值$W_i$. 我 ...

  2. 分布式架构设计(一) --- 面向服务的体系架构 SOA

    1.1 基于TCP协议的RPC 1.1.1 RPC名词解释 RPC的全称是Remote Process Call,即远程过程调用,RPC的实现包括客户端和服务端,即服务调用方和服务提供方.服务调用方发 ...

  3. NOI2001炮兵阵地

    题目传送门 PS:本道题目建议在对状压dp有一定了解的基础下学习,如有不懂可以先去学一下状压dp入门 题目大意:给你n*m个格子,有些格子可以用来部署军队,用P表示,有些则不能,用H表示,如果在一个格 ...

  4. css学习の第五弹—单位和值

    一. >>1.颜色表示方法总结: 1.英文命令颜色 前面几个小节中经常用到的就是这种设置方法: p{color:red;} 2.RGB颜色 这个与 photoshop 中的 RGB 颜色是 ...

  5. WordPress非插件实现评论回复邮件提醒通知

    要想在第一时间知道有人在自己博客留言,然后在第一时间回复留言再第一时间通知邮件者,这就需要WordPress博客拥有邮件通知功能. 先看效果: 评论邮件通知的方法: 1.所有回复都发送邮件通知 登陆博 ...

  6. 记录解决python在spark运行加载第三方库的问题

    一般写python的我们经常会import一些常用的库,然后有时集群环境上的python没有这些库,怎么办呢? 通过一段时间的摸索发现有二种方式可以解决这个问题: 第一种方法: 下载对应python的 ...

  7. 在使用mybatis的selectFromExample时出现Invalid bound statement (not found)错误

    主要原因:运行项目在构建的时候只会默认的去加载resource资源文件里面的资源,其他地方的配置资源不会加载 .故没有读取到mybatis的MapperXml映射 结构如下 ============= ...

  8. AngularJs的resource服务与Rest服务交互

    前言以后补: * 在使用resource服务返回的资源对象后具有与后台数据交互的五大接口:save query delete remove get 五种默认行为: { "get": ...

  9. WinSock 异步I/O模型-3

    重叠I/O(Overlapped I/O) 在 Winsock 中,重叠 I/O(Overlapped I/O)模型能达到更佳的系统性能,高于之前讲过的三种.重叠模型的基本设计原理便是让应用程序使用一 ...

  10. docker环境下使用xdebug进行断点调试

    最近把本地环境切换成了docker的环境,便于快速运行和开发,确实比较给力,但是也遇到了问题,以前的本地xdebug断点调试都用不了,弄了几个小时终于搞定了 docker还是坑多,绕,下面把docke ...