@xiaoqq
2017-10-24T08:40:31.000000Z
字数 6332
阅读 2100
唯品花
JS/CSS无法加载可能有三种情况。
1) JS/CSS请求失败,并且触发onerror事件;
2) JS/CSS请求成功,但是返回空的文本;
3) JS代码加载成功,但是运行报错。
jquery和mars_wap(埋点)脚本引用主站,由于主站的CDN非常稳定,这两个脚本一般情况都不会出现问题。
http://s2.vipstatic.com/js/public/jquery-1.10.2.js
https://3rd.vipstatic.com/mars_wap/mars_wap.js
针对第一种情况,JS/CSS请求失败。给每段脚本的标签加上onerror事件,如脚本加载返回错误,则加载备用脚本,并且触发埋点。
页面顶部
window.loadEvents = [];function onLoadError(e, timeout) {e.timeout = timeout;loadEvents.push(e);}
页面底部
~function() {if(window.loadEvents) {window.loadEvents.forEach(function(e) {var timeout = e.timeout || 0;setTimeout(function() {var marsStr = "";var backupDomain = "http://10.101.145.196:8081"; //备用域名if(e.target instanceof HTMLLinkElement) {var href = e.target.href;marsStr = "css__loadError__" + href +"__"+ window.userId+"__"+window.EP+"";handlderTriggerMarSead({"mars_sead":marsStr});href = href.replace('https://mxfd.vipstatic.com', backupDomain);loadStyles(href);}else if(e.target instanceof HTMLScriptElement) {var src = e.target.src;marsStr = "js__loadError__" + src + "__" + window.userId+"__"+window.EP+"";handlderTriggerMarSead({"mars_sead":marsStr});src = src.replace('https://mxfd.vipstatic.com', backupDomain);loadScript(src);}}, e.timeout);})}}()function loadScript(url) {var script = document.createElement('script');script.type = "text/javascript";script.src = url;document.body.appendChild(script);}function loadStyles(url) {var link = document.createElement("link");link.rel = "stylesheet";link.type = "text/css";link.href = url;var head = document.getElementsByTagName("head")[0];head.appendChild(link);}function handlderTriggerMarSead(opts){if(window.Mar && window.Mar.Seed && window.Mar.Seed.request){window.Mar.Seed.request("mars_sead", "click", opts.mars_sead);}}
然后给每个Link或script标签添加onerror事件。
<link rel="stylesheet" type="text/css" href="${staticDomain}/css/center/centerD.css?v=${tempVersion}" onerror="onStyleLoadError(event)" /><script src="${staticDomain}/script/center/d_center.js?v=${tempVersion}" onerror="onScriptLoadError(event)" charset="utf-8"></script>
对于Angular的兼容方案:
angular.element(document).ready(function () {var isBootstrap = false;app._invokeQueue.forEach(function(list) {if(list[2][0].indexOf("Controller") >0 ) {isBootstrap = true;}})if(isBootstrap) {angular.bootstrap(document.documentElement, ["purchaseApp"]);}});
等所有脚本完全加载,再bootstrap
angular.bootstrap(document.documentElement, ["purchaseApp"]);
针对第二种情况,JS请求成功,但是返回空的文本。给每个JS文件设置一个标识,挂载在windows上,在页面的最底部检测JS的标识是否存在,如果不存在,根据标识,动态加载备用JS,并且发送埋点。
// 嗅探示例 window.version 可以是 window.$ 、window.angularjs 或任意自己定义的全局变量 用于检测cdn返回的文件中是否包含应有的逻辑if (window.version != 1) {// 根据url只会发送一次埋点信息handlderTriggerMarSead();loadScript('http://ms2-m.vipstatic.com/static/page/index/js/index.4513cc84.js');}
通过document.write输出脚本比较合适。
<script src="http://s2.vipstatic.com/js/public/jquery-1.10.2.js "></script><script src="${staticDomain}/script/libs/angular.js" charset="utf-8"></script><script>if(typeof angular == "undefined") {document.write('<script type="text/javascript" src="'+backupDomain + '/script/libs/angular.js'+'"><\/script>');}</script><script src="${staticDomain}/script/requirejs/requiremin.js" charset="utf-8"></script><script>if(typeof require == "undefined") {document.write('<script type="text/javascript" src="'+backupDomain + '/script/requirejs/requiremin.js'+'"><\/script>');}</script><script>FastClick = 0;</script><script src="${staticDomain}/script/main/main.js?v=${tempVersion}" charset="utf-8"></script><script>if(typeof app == "undefined") {document.write('<script type="text/javascript" src="'+backupDomain + '/script/main/main.js' +'"><\/script>');}</script><script src="https://3rd.vipstatic.com/mars_wap/mars_wap.js"></script>
针对第二种情况,CSS请求成功,但是返回空的文本。检测CSS是否加载。
(本来想通过document.styleSheets来判断css是否成功加载,但是跨域的css文件document.styleSheets为空,无法判断...)。
所以,只能检测某个DOM元素的具体样式是否存在。
~function checkStyle() {//获取某个元素具体的样式,这里以body的backgroundColor为例var computedStyle = document.defaultView.getComputedStyle(document.body, null);if(computedStyle.backgroundColor !== "rgb(243, 244, 245)") {var marsStr = "css__showError__" + window.userId+"__"+window.EP+"";handlderTriggerMarSead({"mars_sead":marsStr});}}()
针对第三种情况,添加window.onerror事件,并发送埋点
window.onerror = function (msg, url, lineNo, columnNo, error) {var string = msg.toLowerCase();var substring = "script error";if (string.indexOf(substring) > -1){alert('Script Error: See Browser Console for Detail');} else {var message = ['Message: ' + msg,'URL: ' + url,'Line: ' + lineNo,'Column: ' + columnNo,'Error object: ' + JSON.stringify(error)].join(' - ');console.log(message);}return false;};
发送的错误信息包含:错误位置、错误信息、用户信息。每个埋点按照顺序以__符号分隔。
| 字段 | 说明 |
|---|---|
| error | 错误信息标识 |
| url | 页面地址 |
| src | 脚本地址 |
| errorMessage | 错误信息,若脚本加载失败则loadFailed,若走onerror或trycatch则是errorMessage |
| userId | 用户ID |
| userAgent | 用户设备信息 |
| time | 用户设备时间 |
| ip | 用户设备的ip(暂无,需后端提供) |
安装gulp-css-base64,修改源码,将18行替换为:
var rImages = /url(?:\(['|"]?)(.*?)(?:['|"]?\))(?:.*\/\*base64\*\/)/ig;
修改gulp.js文件,引用gulp-css-base64,并且在cssTask添加上base64的任务:
var base64 = require('gulp-css-base64');gulp.src(cssSrc).pipe(less()).pipe(base64()).pipe(cssmin()).pipe(gulp.dest(cssDst))
在需要转base64的地方添加上/*base64*/注释,指定需要转的文件。例如:
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语句查询出来的数据会有大量的重复数据
SELECT t.*,b.network_typefrom(SELECT a.log_time,a.arg_data_mars,a.app_version,a.app_platform,a.useragent,a.ip,a.user_id,a.hh24,dtfrom vipdw.dw_log_wap_behavior_from_app_hm awhere dt='20170225'AND object_name = 'mxfd_performance') tleft outerJOIN(SELECT user_id,hh24,network_type,dtFROM vipdw.dw_log_app_pageview_ds1where dt='20170225'group by user_id,hh24,network_type,dt,ip ) bon t.user_id=b.user_idAND t.hh24=b.hh24AND 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