流程如下:
graph TD
A[拉取实验配置] --> B
B[归类实验配置] --> C
C[运行多链接实验] --> D
D[发送da_abtest事件] --> E
E[运行可视化实验或编程实验] --> F
F[发送da_abtest事件]
实验调试流程:
graph TD
A[截取url上的凭证] --> B
B[禁止上报所有事件] --> C
C[根据凭证拉取实验配置] --> D
D[运行实验]
可视化实验配置流程:
graph TD
A[截取url上的凭证] --> B
B[禁止上报所有事件和禁止拉取实验配置] --> C
C[拉取可视化配置插件] --> D
D[获取该实验详情] --> E
E[运行实验配置] --> F
F[配置实验条件] --> G
G[保存退出配置]
当客户端拉取到配置后,sdk需要归类实验,当前有三种实验类型:编程实验、多链接实验、可视化实验。
sdk的处理规则:首先确认需要的实验变量,若实验变量头部带有$
符号,表示参与多链接实验;若实验变量头部带有%
符号,表示参与可视化实验;剩下的为编程实验类型。
const getExperimentType = function(variable) {
let type = 1;
if (variable.indexOf('$') === 0) {
type = 3;
} else
if (variable.indexOf('%') === 0) {
type = 2;
}
return type;
}
编程实验需求用户手动获取实验变量的值,故sdk专门设计了这个API。考虑到拉取配置是个异步过程,所以我们希望用户能传入一个回调方法,当配置仍在获取中时,每次调用该API,就将该回调方法保存到本地队列中。一旦配置拉取成功后,就立即执行队列中的回调。
graph TD
A[拉取实验配置中] --> B
B[调用API且传入回调方法] --> C
C[回调保存到本地队列] --> D
D[拉取实验配置完毕] --> E
E[执行队列回调且清空队列]
示例
// 首先调用 abtest.get_variation 方法
DATracker.abtest.get_variation(function(flgs) {
// 再调用 get 方法获取指定变量的值
document.getElementById('ff').style.fontSize = flgs.get('textFont', '10px');
});
多链接实验,需要设计两点:a. sdk内部自动触发;b. 匹配规则实现。
要想自动触发多链接实验,首先sdk归类多链接实验列表,我们只要循环获取到的实验配置,调用 getExperimentType
方法,当返回的type===3时,push进多链接队列中去。然后根据匹配规则确定当前页可参与的多链接实验,我们约定只执行可执行多链接实验队列中首位实验。最后sdk本身调用 get_variation
方法,触发实验。
多链接实验有两类匹配规则:全匹配和模糊匹配。
所谓模糊匹配,指的是创建的多链接实验中,url 不带有参数(?&等..);全匹配就是url带有参数。
若匹配到的实验类型中含有全匹配和模糊匹配,那么优先执行全匹配。 由于变量为填入的url,长度是不可控的,此时拉取的变量是做了md5处理的(取8-24位)。故sdk需要将当前url以及不带参数的url都做md5编码处理。
// 路径
const nowUrlPath = getNowProtocolDommainAndPath();
// url
const nowHref = getNowUrl();
// md5处理,注意 '/'。用户填入url时可带有 '/',或不带 '/',sdk需认为两者是相同的。
const jsMd5NowUrlPath = get8To24Md5(jsMd5(nowUrlPath));
const jsMd5NowUrlPath_ = get8To24Md5(jsMd5(nowUrlPath+ '/'));
const jsMd5NowHref = get8To24Md5(jsMd5(nowHref));
const jsMd5NowHref_ = get8To24Md5(jsMd5(nowHref+ '/'));
// 循环多链接队列
multilinkArr.map((url, i) => {
// 去掉原key的 $符号:'$xxxxx' ==> 'xxxxx'
const key = url.replace(new RegExp('^\\$', 'g'), '');
// 当前用户访问的页面带参数
if (nowHref !== nowUrlPath) {
if (key === jsMd5NowHref || key === jsMd5NowHref_) {
// 此时说明当前为全匹配 ,保存到全匹配队列
} else
if (key === jsMd5NowUrlPath || key === jsMd5NowUrlPath_) {
//key 跟当前path相同,说明为模糊匹配,保存到模糊匹配队列
}
} else
// 当前用户访问的页面不带参数
// 只需判断模糊匹配
if (key === jsMd5NowUrlPath || key === jsMd5NowUrlPath_) {
// key 跟当前path相同,说明为模糊匹配,保存到模糊匹配队列
}
});
可视化实验,需要设计三点:a. sdk内部自动触发;b. 匹配规则实现;c. 动态元素渲染; d. 元素属性变动闪跳; e. 可视化编辑;
这步流程跟多链接类似,区别就是匹配成功的可视化实验,都执行一遍。
可视化实验创建的时候分为:单页面和页面组。由于实验变量都是url,sdk首先需要区分单页面和页面组。设计规则:若变量值中含有 pattern
条件组合是页面组,否则是单页面。
单页面匹配跟多链接实验的匹配规则一样,参考多链接全匹配实现。
页面组匹配根据变量值中的pattern
字段条件判断,只要满足其中任意一个条件,都可以匹配到。
页面组匹配:
if (pattern.relation === 'OR' || pattern.relation === '') {
pattern.conditions.map((con) => {
const field = con.field;
const func = con.func;
const params = con.params;
const nowUrl = getNowUrl();
if (field === 'URL') {
if (func === 'EQUAL') {
// 等于,此时精准匹配; params.indexOf(nowUrl )
}
if (func === 'CONTAIN') {
// 包含, params长度规定为1,故需匹配的条件为 params[0]; nowUrl.indexOf(params[0]) > -1
}
if (func === 'REG_MATCH') {
// 正则,params长度只能等于1,故需匹配的条件为 params[0] ;
const eval2 = eval;
const reg = eval2(nowUrl);
if (reg.test(nowUrl) || reg.test(nowUrl + '/')) {}
}
}
});
}
可视化渲染时,首先需要在页面上找到对应的元素,但动态方式渲染元素时,往往不能马上找到元素,此时实验失败。sdk内部当判断是参与了可视化实验,就先尝试渲染,渲染的过程中将无法找到的元素保存到队列中,一旦监听到页面中该元素已出现,则渲染该元素且显示出来。当前监听方式采用的是定时检测。
经测试,元素属性变化时会闪变,该现象还是很严重影响用户体验的,故sdk提供了一个优化方案。分为两步:
a. 页面隐藏,当拉取配置成功且渲染过一遍后,显示页面,该方法解决了非动态元素的渲染跳动(一定时间内页面也会自动显示出来);
b. 隐藏动态元素,方式就是根据配置值在页面上添加css代码,当找到元素且渲染成功后移除该段css代码;
// 动态元素:render时未找到的元素隐藏
const hidePathStyleSet = function(configArr) {
// 隐藏元素css样式
const styleCss = '{opacity:0 !important;}';
const styleText = '';
configArr.map(item => {
styleText += item.selector + styleCss;
});
const $styleNode = document.getElementById('_hb_abtesting_path_hides');
if ($styleNode) {
if ($styleNode.styleSheet) {
$styleNode.styleSheet.cssText = styleText;
} else {
$styleNode.innerText = '';
$styleNode.appendChild(document.createTextNode(styleText));
}
} else {
const styleNode = document.createElement('style');
const head = document.getElementsByTagName('head')[0];
styleNode.setAttribute('id', '_hb_abtesting_path_hides');
styleNode.setAttribute('type', 'text/css');
if (styleNode.styleSheet) {
styleNode.styleSheet.cssText = styleText;
} else {
styleNode.innerText = '';
styleNode.appendChild(document.createTextNode(styleText));
}
head.appendChild(styleNode);
}
}
当url中含有变量hubble_abtest_editor_key
时,sdk认为进入可视化编辑模式,此时禁止上报任何数据、禁止拉取实验配置,远程拉取可视化编辑插件,
然后接下来的可视化编辑跟sdk没有任何关系,这样设计最大限度的保证sdk的功能独立性。
由于可视化编辑讲解有些复杂,具体可以参考我写的文章:web在线页面编辑实现-abtest可视化实验。
实验调试设计跟可视化类似,都是根据查看url上是否包含某个字段判断进入指定模式, 禁止上报数据到服务器,远程拉取插件。
最开始我们讲解过,此时sdk需要拉取实验配置,但是参数值需从url上获取,同时需禁止本地缓存功能。
设计如下:
graph TD
A[url中含有hubble_abtest_debug_key] --> B
B[将凭证保存到本地seeionStorage] --> C
C[禁止本地缓存和禁止数据上报到服务器] --> D
D[拉取远程控制js文件] --> E
E[拉取配置的userId参数值设置为hubble_abtest_debug_key的值,拉取实验配置] --> F
F[触发的事件保存到队列中,等到远程js拉取完毕初始化后推送给它] --> G
G[页面展示出优化指标事件] --> H
H[切换页面后查看本地seeionStorage有凭证] --> C
当关闭当前窗口,退出调试模式。