@xiaoqq
2017-10-24T08:40:31.000000Z
字数 6332
阅读 2002
唯品花
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_type
from
(SELECT a.log_time,
a.arg_data_mars,
a.app_version,
a.app_platform,
a.useragent,
a.ip,
a.user_id,
a.hh24,
dt
from vipdw.dw_log_wap_behavior_from_app_hm a
where dt='20170225'
AND object_name = 'mxfd_performance') t
left outer
JOIN
(SELECT user_id,
hh24,
network_type,
dt
FROM vipdw.dw_log_app_pageview_ds1
where dt='20170225'
group by user_id,hh24,network_type,dt,ip ) b
on t.user_id=b.user_id
AND t.hh24=b.hh24
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