web端数据采集库sdk支持abtest设计

sdk支持abtest功能

  1. 现在web端A/B 实验支持三种类型:编程实验、多链接实验、可视化实验,sdk在用户客户端的功能就是拉取实验配置,执行实验。

流程如下:

graph TD

A[拉取实验配置] --> B
B[归类实验配置] --> C
C[运行多链接实验] --> D
D[发送da_abtest事件] --> E
E[运行可视化实验或编程实验] --> F
F[发送da_abtest事件]
  1. 在A/B 实验平台上,js-sdk实验支持的功能:实验调试、可视化实验配置。

实验调试流程:

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. 匹配规则实现。

  1. 自动触发

要想自动触发多链接实验,首先sdk归类多链接实验列表,我们只要循环获取到的实验配置,调用 getExperimentType方法,当返回的type===3时,push进多链接队列中去。然后根据匹配规则确定当前页可参与的多链接实验,我们约定只执行可执行多链接实验队列中首位实验。最后sdk本身调用 get_variation方法,触发实验。

  1. 匹配规则

多链接实验有两类匹配规则:全匹配和模糊匹配。

所谓模糊匹配,指的是创建的多链接实验中,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. 可视化编辑;

  1. 自动触发

这步流程跟多链接类似,区别就是匹配成功的可视化实验,都执行一遍。

  1. 匹配规则

可视化实验创建的时候分为:单页面和页面组。由于实验变量都是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 + '/')) {}
      }
    }
  });
}
  1. 动态元素渲染

可视化渲染时,首先需要在页面上找到对应的元素,但动态方式渲染元素时,往往不能马上找到元素,此时实验失败。sdk内部当判断是参与了可视化实验,就先尝试渲染,渲染的过程中将无法找到的元素保存到队列中,一旦监听到页面中该元素已出现,则渲染该元素且显示出来。当前监听方式采用的是定时检测。

  1. 元素属性变动闪跳

经测试,元素属性变化时会闪变,该现象还是很严重影响用户体验的,故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);
    }
}
  1. 可视化编辑

当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

当关闭当前窗口,退出调试模式。

猜你喜欢

转载自blog.csdn.net/ihaveahappyfamily/article/details/81236080
今日推荐