zoukankan      html  css  js  c++  java
  • Beforeunload打点丢失原因分析及解决方案

    淘宝的鱼相在 2012 年 8 月份发表了一篇文章,里面讲述了他们通过一个月的数据采集试验,得到的结果是:如果在浏览器的本页面刷新之前发送打点请求,各浏览器都有不同程度的点击丢失情况,具体点击丢失率统计大家请看下图(数据日期为 2012 年 7 月份):

    alt

      从图中可以看出,chrome,safari 这类 webkit 内核的浏览器在本页刷新之前发送打点,导致的丢失最为严重,分别为 61%,76%,而 ie8 丢失的情况最少,为7%。 (具体大家可以参看此文:http://ued.taobao.com/blog/?p=116 )

      原因分析:

      基于这种现象的产生,抛开打点服务器的处理性能和网络网速因素,我们从前端的角度来分析一下:

      当点击浏览器的当前页面某个元素后,当前页面创建 image 对象,并把这个 image 对象的 src 设为指向打点服务器的 url,发送打点请求。接着,当前页又向页面服务器发送页面跳转请求。假设页面服务器很快就返回了请求的 html, 则浏览器窗口接收到页面服务器的响应后,开始卸载保存在用户内存中的跟当前页面的有关的所有元素,包括刚才创建的用来向打点服务器发送打点的 image 对象。假设这时打点服务器对这个 image 发送的打点请求还在处理阶段,比如正在向数据库插入数据,还没有做 response 响应。这时,由于页面卸载了,image 对象被销毁了,该对象发送的 src 请求也就被终止了。导致这个打点失败了。类似于垃圾回收机制的影响。如果刚创建的 image 元素立即被内存垃圾回收了,而这个图片的 HTTP 请求尚未建立,那么在被回收时这个请求就会被取消,导致打点并没有真正发出。一个 http 请求的成功,必须是与后端服务器握手的成功。根据 DW 的胡大军检测到的数据,后端服务器监测到 3 次 tcp 协议的请求后,http 请求就被终止了。从这种现象上说明,浏览器在页面跳转之前确实发送了打点请求,由于页面跳转过快,发送打点的 image 对象因页面卸载而销毁了,请求也就被终止了。

      具体示意图如下:alt

      搜索端应用 searchweb 曾经做过试验,如果 searchweb 端响应延迟 100ms 后返回 html 数据,这种在页面卸载之前发送的请求打点(我们这里称它为 Beforeunload 打点)的回收率就明显上升,差不多得到了 100% 的回收率。页面服务器响应时间越长,Beforeunload 打点丢失率越低。因为页面服务器响应时间变长后,打点服务器有足够的时间处理打点请求, 然后返回给 image 对象做 response 响应。在本页面卸载刷新之前,image 对象的 src 请求已经成功得到了响应。这时再销毁该对象,对打点丢失已经没什么影响了。可以说,只要用来打点的 image 对象在打点成功之前没有被销毁,打点就不会丢失。如果链接跳转的方式是新窗口打开的,也就不会发生打点丢失的情况。因为当前页创建的打点 image 对象被没有被销毁。

      解决方案

      找到了 Beforeunload 打点丢失的原因,我们再来思考一下解决方案:

      因为页面创建的 image 对象在打点请求还没响应之前就被卸载了。如果单纯提升打点服务器性能,确实能加快 image 打点请求的响应返回,减少 Beforeunload 打点丢失情况。问题是,打点服务器要提升多少性能才是合适的?其实是页面服务器(应用服务器)跟打点服务器的一场竞赛。如果页面服务器性能大大提升了,而打点服务器没有提升,那么差距又拉大了。 又或者像 searchweb 做的试验那样,页面服务器(应用服务器)做延迟响应处理,这样 Beforeunload 打点丢失就能得到有效遏制。问题是这其实是对用户体验的极大伤害。现如今大家都在拼命提升应用页面服务器的性能,让页面能加载的更快,用户使用网页感觉更流畅。为了能在服务后端打上点,我们却要自己的应用延迟响应,跟我们提升用户体验的目标背道而驰。要知道,任何软件的应用,良好的用户体验是第一位的。所以,此路不通也。

      那有没有一种更好的办法?比如在页面刷新之前缓存打点数据,页面卸载刷新后,把原来页面刷新之前保存的打点数据取出来,再打点出去?这样,刷新后的页面打点跟点击 pv 基本上就是1:1 了,因为 pv 的计算也是根据跳转后的页面 url 来统计的。答案是:还真有。

      在浏览器页面被卸载的过程中,除了 window.name 属性对象外,其他对象元素都被销毁了。所以我们在页面卸载之前把请求打点的数据保存在 window.name 中。然后,页面刷新后,再取出这个 window.name 对象中保存的打点数据,发送打点请求。

      如果单存要存储打点数据,让该数据在页面刷新之后仍然能够被访问,有 cookie 对象,高级浏览器还支持 localStorage,为什么只推荐 window.name ? 原因如下:

    1. window.name 没有类似于 cookie,localStorage 的跨域问题。如果从 www.taobao.com 跳到 www.tmall.com,天猫的页面仍然能够得到在淘宝页面设置的 window.name 的值。而 cookie 只能跨主域。Localstorage 则不能跨域,连跨主域都不行,所以,在上面的场景中,如果使用 cookie 或者 localstorage,天猫页面无法获取淘宝页面设置的 cookie 或者 localstorage;

    2. Window.name 所有浏览器都支持,无论是 webkit 内核还是 IE 系列,所有浏览器都一概支持,而且表现一致。

    3. 页面刷新打点完毕后,原来被保存的打点数据已经没有用了,数据保存形式应该是临时性质的。cookie,localstorage 对象的设计是用来存储持久数据的,而 window.name 的设计,就是为保存页面临时数据的。如果页面窗口关掉了,内存回收了 widow 对象,window.name 也就不存在了。两者的需求与用途一致。

      如此看来,用 window.name 来存储 Beforeunload 打点请求的数据确实是个不错的主意,但是还有一个问题:如果 window.name 属性对象已经被应用程序使用了,也就是 window.name 已经被应用设为某个值了,这时我们再修改这个 window.name,岂不是对应用程序造成了破坏?

      答案是:没有关系。我们在页面跳转前,拼接完打点串后,可以这样写

    window.name=window.name+”|%”+logURL;

      其中,logURL 是要打点的请求串。通过这样设置 window.name,原来应用程序的 window.name 的数据仍然被保存着。在页面跳转后的打点 js 中,可以这样写打点代码:

      var windowUrl=$.trim (window.name);
      if(windowUrl && windowUrl.indexOf ("|%")!==-1){
        var urlArray=windowUrl.split ("|%"),orginName=urlArray[0];
        windowUrl=urlArray[1];    
      //把 window.name 归还给应用程序   window.name=orginName;        
        //发送打点请求   sendByImg (windowUrl);
    }

      上面这段页面曝光打点的代码,放在标签里面,类似于 1688 中文站的 beacon.js,专门用来打点。因为打点代码在 head 标签里,一般在所有应用代码之前执行。(一般应用代码在 domready 的时候执行)所以在该代码执行完后,window.name 已经被设置为原来应用的值了。这样对应用造成的破坏也就不存在了。

      解决方案的示意图如下:

    alt

      解决方案数据验证效果

      蓝色为 Beforeunload 打点,红色为用 window.name 先存储打点数据,页面刷新跳转后,再从 window.name 取回打点数据,曝光打出的点。 Chrome 浏览器下的平均数据如下:

    alt

    alt

      可以看到,通过 window.name 的解决方式,打点效果提升了 13%。

      IE 平台下的总平均回收效果如图(包括 ie6,ie7,ie8,ie9,ie10 总和):

    alt

    alt

      IE 系列各浏览器的平均回收效果如图:

    alt

      (注:目前中文站的用到的 fdev-min.js 依赖的 jQuery1.7.2 的 attr 方法有个 bug,当 IE10 浏览器的 ie7 文档模式下调用 attr 方法时,程序会抛异常,导致了 window.name 不能被赋值。上图中,IE10 有可能因为受此影响,表现不如 Beforeunload 打点。关于这个 jQuery bug 的详细介绍,有兴趣的同学,可以看看这篇 jQuery 官网的 bug 帖 http://bugs.jquery.com/ticket/12577

    alt

    alt

      方案总结

      总体而言,新方案跟无痕打点的 Beforeunload 打点方式时相比,在 ie 上略有提升,chrome 浏览器上,提升最为明显,相比原来提升了 13%。这种方案还是很有效果的。

  • 相关阅读:
    POJ 2752 Seek the Name, Seek the Fame
    POJ 2406 Power Strings
    KMP 算法总结
    SGU 275 To xor or not to xor
    hihocoder 1196 高斯消元.二
    hihoCoder 1195 高斯消元.一
    UvaLive 5026 Building Roads
    HDU 2196 computer
    Notions of Flow Networks and Flows
    C/C++代码中的笔误
  • 原文地址:https://www.cnblogs.com/timejs/p/4787720.html
Copyright © 2011-2022 走看看