[关闭]
@xiaoqq 2017-10-24T08:40:31.000000Z 字数 6332 阅读 2002

针对JS/CSS无法加载的降级处理

唯品花


JS/CSS无法加载可能有三种情况。
1) JS/CSS请求失败,并且触发onerror事件;
2) JS/CSS请求成功,但是返回空的文本;
3) JS代码加载成功,但是运行报错。

  1. jquery和mars_wap(埋点)脚本引用主站,由于主站的CDN非常稳定,这两个脚本一般情况都不会出现问题。

    http://s2.vipstatic.com/js/public/jquery-1.10.2.js
    https://3rd.vipstatic.com/mars_wap/mars_wap.js

  2. 针对第一种情况,JS/CSS请求失败。给每段脚本的标签加上onerror事件,如脚本加载返回错误,则加载备用脚本,并且触发埋点。
    页面顶部

    1. window.loadEvents = [];
    2. function onLoadError(e, timeout) {
    3. e.timeout = timeout;
    4. loadEvents.push(e);
    5. }

    页面底部

    1. ~function() {
    2. if(window.loadEvents) {
    3. window.loadEvents.forEach(function(e) {
    4. var timeout = e.timeout || 0;
    5. setTimeout(function() {
    6. var marsStr = "";
    7. var backupDomain = "http://10.101.145.196:8081"; //备用域名
    8. if(e.target instanceof HTMLLinkElement) {
    9. var href = e.target.href;
    10. marsStr = "css__loadError__" + href +"__"+ window.userId+"__"+window.EP+"";
    11. handlderTriggerMarSead({"mars_sead":marsStr});
    12. href = href.replace('https://mxfd.vipstatic.com', backupDomain);
    13. loadStyles(href);
    14. }else if(e.target instanceof HTMLScriptElement) {
    15. var src = e.target.src;
    16. marsStr = "js__loadError__" + src + "__" + window.userId+"__"+window.EP+"";
    17. handlderTriggerMarSead({"mars_sead":marsStr});
    18. src = src.replace('https://mxfd.vipstatic.com', backupDomain);
    19. loadScript(src);
    20. }
    21. }, e.timeout);
    22. })
    23. }
    24. }()
    25. function loadScript(url) {
    26. var script = document.createElement('script');
    27. script.type = "text/javascript";
    28. script.src = url;
    29. document.body.appendChild(script);
    30. }
    31. function loadStyles(url) {
    32. var link = document.createElement("link");
    33. link.rel = "stylesheet";
    34. link.type = "text/css";
    35. link.href = url;
    36. var head = document.getElementsByTagName("head")[0];
    37. head.appendChild(link);
    38. }
    39. function handlderTriggerMarSead(opts){
    40. if(window.Mar && window.Mar.Seed && window.Mar.Seed.request){
    41. window.Mar.Seed.request("mars_sead", "click", opts.mars_sead);
    42. }
    43. }

    然后给每个Link或script标签添加onerror事件。

    1. <link rel="stylesheet" type="text/css" href="${staticDomain}/css/center/centerD.css?v=${tempVersion}" onerror="onStyleLoadError(event)" />
    2. <script src="${staticDomain}/script/center/d_center.js?v=${tempVersion}" onerror="onScriptLoadError(event)" charset="utf-8"></script>

    对于Angular的兼容方案:

    1. angular.element(document).ready(function () {
    2. var isBootstrap = false;
    3. app._invokeQueue.forEach(function(list) {
    4. if(list[2][0].indexOf("Controller") >0 ) {
    5. isBootstrap = true;
    6. }
    7. })
    8. if(isBootstrap) {
    9. angular.bootstrap(document.documentElement, ["purchaseApp"]);
    10. }
    11. });

    等所有脚本完全加载,再bootstrap

    1. angular.bootstrap(document.documentElement, ["purchaseApp"]);
  3. 针对第二种情况,JS请求成功,但是返回空的文本。给每个JS文件设置一个标识,挂载在windows上,在页面的最底部检测JS的标识是否存在,如果不存在,根据标识,动态加载备用JS,并且发送埋点。

    1. // 嗅探示例 window.version 可以是 window.$ 、window.angularjs 或任意自己定义的全局变量 用于检测cdn返回的文件中是否包含应有的逻辑
    2. if (window.version != 1) {
    3. // 根据url只会发送一次埋点信息
    4. handlderTriggerMarSead();
    5. loadScript('http://ms2-m.vipstatic.com/static/page/index/js/index.4513cc84.js');
    6. }

    通过document.write输出脚本比较合适。

    1. <script src="http://s2.vipstatic.com/js/public/jquery-1.10.2.js "></script>
    2. <script src="${staticDomain}/script/libs/angular.js" charset="utf-8"></script>
    3. <script>
    4. if(typeof angular == "undefined") {
    5. document.write('<script type="text/javascript" src="'+backupDomain + '/script/libs/angular.js'+'"><\/script>');
    6. }
    7. </script>
    8. <script src="${staticDomain}/script/requirejs/requiremin.js" charset="utf-8"></script>
    9. <script>
    10. if(typeof require == "undefined") {
    11. document.write('<script type="text/javascript" src="'+backupDomain + '/script/requirejs/requiremin.js'+'"><\/script>');
    12. }
    13. </script>
    14. <script>
    15. FastClick = 0;
    16. </script>
    17. <script src="${staticDomain}/script/main/main.js?v=${tempVersion}" charset="utf-8"></script>
    18. <script>
    19. if(typeof app == "undefined") {
    20. document.write('<script type="text/javascript" src="'+backupDomain + '/script/main/main.js' +'"><\/script>');
    21. }
    22. </script>
    23. <script src="https://3rd.vipstatic.com/mars_wap/mars_wap.js"></script>
  4. 针对第二种情况,CSS请求成功,但是返回空的文本。检测CSS是否加载。
    (本来想通过document.styleSheets来判断css是否成功加载,但是跨域的css文件document.styleSheets为空,无法判断...)。
    所以,只能检测某个DOM元素的具体样式是否存在。

    1. ~function checkStyle() {
    2. //获取某个元素具体的样式,这里以body的backgroundColor为例
    3. var computedStyle = document.defaultView.getComputedStyle(document.body, null);
    4. if(computedStyle.backgroundColor !== "rgb(243, 244, 245)") {
    5. var marsStr = "css__showError__" + window.userId+"__"+window.EP+"";
    6. handlderTriggerMarSead({"mars_sead":marsStr});
    7. }
    8. }()
  5. 针对第三种情况,添加window.onerror事件,并发送埋点

    1. window.onerror = function (msg, url, lineNo, columnNo, error) {
    2. var string = msg.toLowerCase();
    3. var substring = "script error";
    4. if (string.indexOf(substring) > -1){
    5. alert('Script Error: See Browser Console for Detail');
    6. } else {
    7. var message = [
    8. 'Message: ' + msg,
    9. 'URL: ' + url,
    10. 'Line: ' + lineNo,
    11. 'Column: ' + columnNo,
    12. 'Error object: ' + JSON.stringify(error)
    13. ].join(' - ');
    14. console.log(message);
    15. }
    16. return false;
    17. };

埋点的字段

发送的错误信息包含:错误位置、错误信息、用户信息。每个埋点按照顺序以__符号分隔。

字段 说明
error 错误信息标识
url 页面地址
src 脚本地址
errorMessage 错误信息,若脚本加载失败则loadFailed,若走onerror或trycatch则是errorMessage
userId 用户ID
userAgent 用户设备信息
time 用户设备时间
ip 用户设备的ip(暂无,需后端提供)

less中图片转Base64解决方案

  1. 安装gulp-css-base64,修改源码,将18行替换为:

    1. var rImages = /url(?:\(['|"]?)(.*?)(?:['|"]?\))(?:.*\/\*base64\*\/)/ig;
  2. 修改gulp.js文件,引用gulp-css-base64,并且在cssTask添加上base64的任务:

    1. var base64 = require('gulp-css-base64');
    2. gulp.src(cssSrc).pipe(less()).pipe(base64()).pipe(cssmin()).pipe(gulp.dest(cssDst))
  3. 在需要转base64的地方添加上/*base64*/注释,指定需要转的文件。例如:

    1. background: url('@{staticDomain}/images/left_arrow.png?@{pictrueVersion}') /*base64*/no-repeat;

    注意:/*base64*/一定要写在分号之前,url之后。

前端性能监控指标

性能参数

参数 类型 描述
ext_domain string 域名
ext_path string 页面
t_unload number 上个文档的卸载时间
t_redirect number 页面重定向的时间
t_dns number DNS解析时间
t_tcp number 服务器连接时间
t_request number 服务器响应时间
t_response number 网页文档下载时间
t_paint number 首次渲染时间(首屏时间,IOS上不支持)
t_dom number DOM Ready时间(阶段)
t_domready number DOM Ready时间(总和)
t_load number onload时间(阶段)
t_onload number onload时间(总和)
t_white number 白屏时间
t_all number 全部过程时间

大数据埋点字段

参数 类型 描述
log_time DateTime 埋点记录的时间
arg_data_mars json 性能指标的数据
app_version string APP版本号
app_platform string(iphone/ipad/android) 使用平台
useragent string 客户端信息
ip string 用户ip
user_id int 用户userid
network_type string 用户网络类型

数据处理步骤:
1. 使用excel删除重复项;
2. 对于

目前存在的问题:
1. 使用以下这段SQL语句查询出来的数据会有大量的重复数据

  1. SELECT t.*,
  2. b.network_type
  3. from
  4. (SELECT a.log_time,
  5. a.arg_data_mars,
  6. a.app_version,
  7. a.app_platform,
  8. a.useragent,
  9. a.ip,
  10. a.user_id,
  11. a.hh24,
  12. dt
  13. from vipdw.dw_log_wap_behavior_from_app_hm a
  14. where dt='20170225'
  15. AND object_name = 'mxfd_performance') t
  16. left outer
  17. JOIN
  18. (SELECT user_id,
  19. hh24,
  20. network_type,
  21. dt
  22. FROM vipdw.dw_log_app_pageview_ds1
  23. where dt='20170225'
  24. group by user_id,hh24,network_type,dt,ip ) b
  25. on t.user_id=b.user_id
  26. AND t.hh24=b.hh24
  27. AND t.dt=b.dt

2.当数据大于5000条时,导出的JSON格式有误,无法解析。

错误日志

大数据埋点字段

参数 类型 描述
log_time DateTime 埋点记录的时间
object_name string 性能指标的数据
app_version string APP版本号
app_platform string(iphone/ipad/android) 使用平台
useragent string 客户端信息
ip string 用户ip
user_id int 用户userid
network_type string 用户网络类型

https://gw.alicdn.com/bao/uploaded/i4/TB1SoL6PVXXXXbTXFXXXXXXXXXX_!!0-item_pic.jpg_760x760Q100s0.jpg

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注