白屏来源
上一版部门用的前端结构是python || lua渲染的html页面 + seajs + js模板 + less,但是这种情况发现对应不懂服务端渲染页面,或者服务端人员来说,在配合上存在工作不明,比如渲染的html应该由谁来维护,毕竟渲染的页面还是需要从服务端取数据的,以及在互相配合的过程中存在知识差异效率低的情况。
所以我们重构了,改成 backbone + modjs + js模板 + less, 打包模块也由grunt改成fis了。
白屏现象
重构了两个月,终于要上线了,好激动啊
...
白屏访问不了...白屏访问不了...白屏访问不了...
我去,我都没有重现啊
白屏定位与数量统计
既然出现了反馈,那肯定就是有问题了,但是本机又没有重现,该如何定位呢?
首先,还是要确定下白屏的数量占比。
统计方式,就是监听某个主DIV的变化(因为是单页面的应用,所以总会有个入口DIV来监听),白屏即是该div没有在规定时间内被放入东西,所以只要在规定时间内该DIV没有变化,那就可以进行白屏统计了。
最后统计上来,发现白屏占比在6%左右,数量还是蛮大的。
(如果说还需要统计网速之类的,因为我们的主程序js是通过async挂上去的,也可以在规定时间内检测加载到哪个script了,由此来确定程序的加载情况如何)
(如果说还需要统计API的调用情况的,比如是否timeout了,那可以在backbone的model里面的parseError进行监听)
白屏问题原因分析
既然问题出来了,数量出来了,那怎么找出原因就显得很重要了。
通过限速,重现用户反馈情况,步骤代码分析,最后确定:
- 1、网速渣渣导致相关依赖资源加载超时
- 2、客户端存在bug,缓存模块错乱,不缓存js等后来挂起的文件,以及乱缓存index.html
白屏解决
1、网速渣渣
针对这个情况,我们发现会出现4个现象
- 一、首页直出时间过长
- 二、依赖js没加载完全
- 三、文件依赖关系表map.js加载不正确
- 四、接口调用时间过长
对于首页直出时间过长,这个对于前后端分离的应用,基本都是会遇见的,毕竟首页的数据都需要通过再调API去拼接,加载模板等,这都是需要时间的,如果网速不行,那这个时间就更长的,但是考虑到需要做前后端分离,总不能还是以渲染模板的方式,那到底应该怎么才能确保前后端分离,又能够加快直出时间。
这个时候就需要nodejs直出了,通过在服务端增加一个nodejs中间层,由nginx将前端的请求转发到nodejs上,nodejs响应请求,加载资源,向底层的cgi进行API请求,之后进行拼接,返回html页面,这样资源跟api的请求时间都在服务端完成,缩短了时间,至于模板之类的,还是能够用到前端。当然nodejs也会有请求资源错误的情况,这个时候就需要返回错误标志给前端,前端再发起原来的异步请求,这种方式相当于一种容灾保障。
因为是应用方式,所以总是难免存在一些基础依赖,比如modjs,backbone, underscore, jquery等,这种一般都会通过打包成一个js来减少http请求以及文件大小。
但是不管怎么打这个文件数量还是会蛮大的,比如打了100k,那在网速渣渣,比如20k/s的情况还是需要5s的
再加上其他一些首页资源,那加载时间超过15s还是有可能的。
针对这种情况,只能通过打包模式,加载资源的模式进行改进。强烈按照“首页必须”进行开发,按需加载,其他的资源可以放在二屏,毕竟首页决定着是否还会继续使用。
文件依赖map.js加载失败
map.js主要是由fis打包插入到页面,用于解析模块之间的依赖关系的,这个文件是个超级入口
在网速渣渣,一旦这个文件加载失败了,那其他都不用玩了。
解决方法就是,尽量减少文件夹的嵌套,文件名不要过长,因为map.js会按照这种进行解析,其实也就是尽量减少map.js的大小
另外,因为fis中map.js的加载方式是require.resoureMap,之中的依赖关系是按照字符串的,没有使用变量,这个也可以按照seajs.config的方式进行
最后就是map.js容灾了,因为map.js加载失败,程序的启动入口require.async会直接请求路径,比如require.async(‘index/app‘),如果map.js加载失败,会变成请求index/app这个路径,这个时候,我们就可以在这里加入一个页面,用于重试加载页面等。
另外,接口调用时间过长也会导致单页面应用的加载时间过长,这种我们主要是前端需要给接口设置timeout时间,Backbone.async里面可以设置
2、客户端缓存bug
客户端随意缓存index.html,这种是大坑,只能通过url中加上随机数进行更新
资源不缓存主要是没有带上if-modify-since, if-none-match这种需要加上304验证
白屏启发
做好性能检测,以及限速检测,订制应用性能数量级,比如10k/s加载时间应该在什么范围内
另外,对于可订制的客户端,也可以仿照(manifest/appcache,不完善不适合)做一个缓存机制,即是判断服务器版本是否与客户端保存的资源一致,不一致即下载新的,一致即直接使用本地的,这样就变成一个类本地应用了。