作者:今日头条技术

链接:https://techblog.toutiao.com/2018/06/05/ru-he-jing-que-tong-ji-ye-mian-ting-liu-shi-chang/

1、背景

页面停留时间(Time on Page)简称 Tp,是网站分析中很常见的一个指标,用于反映用户在某些页面上停留时间的长短,传统的Tp统计方法会存在一定的统计盲区,比如无法监控单页应用,没有考虑用户切换Tab、最小化窗口等操作场景。基于上述背景,重新调研和实现了精确统计页面停留时长的方案,需要 兼容单页应用和多页应用,并且不耦合或入侵业务代码。

2、分析

我们可以把一个页面生命周期抽象为三个动作:「进入」、「活跃状态切换」、「离开」

如下图,计算页面停留时长既如何监控这三个动作,然后在对应触发的事件中记录时间戳,比如要统计活跃停留时长就把 active 区间相加即可,要统计总时长既 tn -t0 。

2.1 如何监听页面的进入和离开?

对于常规页面的 首次加载、页面关闭、刷新 等操作都可以通过 window.onload 和 window.onbeforeunload 事件来监听页面进入和离开,浏览器前进后退可以通过 pageshow 和 pagehide 处理。

  • load / beforeunload

  • pageshow / pagehide

对于单页应用内部的跳转可以转化为两个问题:

  • 监听路由变化

  • 判断变化的URL是否为不同页面 。

2.1.1 监听路由变化

目前主流的单页应用大部分都是基于 browserHistory (history api) 或者 hashHistory 来做路由处理,我们可以通过监听路由变化来判断页面是否有可能切换。注意是有可能切换,因为URL发生变化不代表页面一定切换,具体的路由配置是由业务决定的(既URL和页面的匹配规则)。

browserHistory

路由的变化本质都会调用 History.pushState() 或 History.replaceState() ,能监听到这两个事件就能知道。通过 popstate 事件能解决一半问题,因为 popstate 只会在浏览器前进后退的时候触发,当调用 history.pushState() or history.replaceState() 的时候并不会触发。

The popstate event is fired when the active history entry changes. If the history entry being activated was created by a call to history.pushState() or was affected by a call to history.replaceState(), the popstate event’s state property contains a copy of the history entry’s state object.

Note that just calling history.pushState() or history.replaceState() won’t trigger apopstateevent. The popstate event will be triggered by doing a browser action such as a click on the back or forward button (or calling。history.back() or history.forward() in JavaScript).

这里需要通过猴子补丁(Monkeypatch)解决,运行时重写 history.pushState 和 history.replaceState 方法:

let _wr =  function (type) {  let orig = window.history[type]return  function () {let rv = orig.apply(this, arguments)let e = new Event(type.toLowerCase())e.arguments = argumentswindow.dispatchEvent(e)return rv}}
window.history.pushState = _wr('pushState')
window.history.replaceState = _wr('replaceState')
window.addEventListener('pushstate',  function (event) {})
window.addEventListener('replacestate',  function (event) {})

hashHistory

hashHistory 的实现是基于 hash 的变化,hash 的变化可以通过 hashchange 来监听

2.1.2 判断URL是否为不同页面

方案1: 客户端定义

通过业务方在初始化的时候配置页面规则,然后JS通过URL匹配不同的规则来区分不同的页面,这种方案在客户端数据上报的时候就已经明确了不同的页面,伪代码:

new Tracer({  rules: [{ path: '/index' },{ path: '/detail/:id' },{ path: '/user', query: {tab: 'profile'} }])

方案2: 数据分析平台定义

假设我们最终上报后有一个数据分析平台来展现,我们可以在类似数据平台来配置页面规则,这样在客户端实现的代码逻辑就不需要区分页面,而是每次URL发生变化就将数据上报,最终通过数据平台配置的页面URL规则来求和、过滤数据等。

当数据展现平台不支持配置URL规则来区分页面的时候,可以采用方案1;当有数据平台支持的时候采用方案2更合理;

2.1.3 对于页面进入和离开相关事件整理

2.2 如何监听页面活跃状态切换?

可以通过 Page Visibility API 以及在 window 上声明 onblur/onfocus 事件来处理。

2.2.1 Page Visibility API

一个网页的可见状态可以通过 Page Visibility API 获取,比如当用户 切换浏览器Tab、最小化窗口、电脑睡眠 的时候,系统API会派发一个当前页面可见状态变化的 visibilitychange 事件,然后在事件绑定函数中通过 document.hidden 或者 document.visibilityState 读取当前状态。

document.addEventListener('visibilitychange',  function (event) {  console.log(document.hidden, document.visibilityState)})

2.2.2 onblur/onfocus

可以通过 Page Visibility API 以及在 window 上声明 onblur/onfocus 事件来处理。对于PC端来说,除了监听上述相关事件外,还可以考虑监听鼠标行为,比如当一定时间内鼠标没有操作则认为用户处于非活跃状态。

2.3 什么时机上报数据?

2.3.1 页面离开时上报

对于页面刷新或者关闭窗口触发的操作可能会造成数据丢失

2.3.2 下次打开页面时上报

会丢失历史访问记录中的最后一个页面数据

目前采用的方案2,对于单页内部跳转是即时上报,对于单页/多页应用触发 window.onbeforeunload 事件的时候会把当前页面数据暂存在 localStorage 中,当用户下次进入页面的时候会把暂存数据上报。有个细节问题,如果用户下次打开页面是在第二天,对于统计当天的活跃时长会有一定的误差,所以在数据上报的同时会把该条数据的页面进入时间/离开时间带上。

3、设计

3.1 UML类关系图

Tracer

核心类,用来实例化一个监控,对原生事件和自定义事件的封装,监听 enter activechange exit 事件来操作当前 Page 实例。

P.S. 取名来自暴雪旗下游戏守望先锋英雄猎空(Tracer),直译为:追踪者。

Page
页面的抽象类,用来实例化一个页面,封装了 enter exit active inactive 等操作,内部通过 state 属性来维护当前页面状态。

3.2 事件派发关系图

4、兼容性

Desktop

Mobile

5、思考

对于页面停留时长的定义可能在不同场景会有差异,比如内部业务系统或者OA系统,产品可能更关心用户在页面的活跃时长;而对于资讯类型的产品,页面可见时长会更有价值。单一的数据对业务分析是有限的,所以在具体的代码实过程中我们会把停留时长分三个指标,这样能更好的帮助产品/运营分析。

  • active 页面活跃时长

  • visible 页面可见时长 //仅支持Desktop

  • duration 页面总停留时长

6、参考

  • https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onhashchange

  • https://developer.mozilla.org/en-US/docs/Web/Events/popstate

  • https://developer.mozilla.org/en-US/docs/Web/API/PageVisibilityAPI

  • https://stackoverflow.com/questions/4570093/how-to-get-notified-about-changes-of-the-history-via-history-pushstate

关注公众号,查看更多优质文章
最近,整理一份Java资料《Java从0到1》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。获取方式:关注公众号并回复 Java 领取,更多Java内容陆续奉上。
明天见(。・ω・。)ノ♡

如何精确统计用户在页面的停留时长?相关推荐

  1. 如何精确统计页面停留时长

    关注公众号 前端开发博客,回复"加群" 加入我们一起学习,天天进步 作者:今日头条技术 链接:https://techblog.toutiao.com/2018/06/05/ru- ...

  2. HTML5停留时长统计,平均停留时间

    本词条缺少概述图,补充相关内容使词条更完整,还能快速升级,赶紧来编辑吧! 这个指标由于其看上去是一个很容易理解的度量指标(不就是访客在这浏览这个网站时花了多少时间吗).因此不少管理人员特别是其他非网站 ...

  3. Android 如何正确统计页面停留时长

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/112546517 本文出自[赵彦军的博客] 在Android中经常有统计页面停留时长 ...

  4. react利用useEffect记录用户在当前页面停留时长

    项目场景: 小程序项目中需要记录用户在当前页面停留的时长,下意识想到在useState中记录一个时间戳,在useEffect中的return中获取一个时间戳,减去state中记录的时间戳,用得到的值取 ...

  5. Redis计数器统计小程序用户停留时长

    业务需求 统计小程序的用户停留时长 不需要实时统计,所以按照天为维度 使用Redis的hash形式存并使用计数器累加时长,凌晨定时持久化前一天的数据到DB 注:一些其它统计也可以使用此种方式来 使用R ...

  6. 计算页面停留时长的另类方式

    计算页面停留时长,往常计算也页面留时长都需要跑spark或这mr任务来实现,如果能跑sql来实现那是最好不过了(sql是最好的语言),废话不多说,直接搞起 注意:这里使用的计算引擎是presto 首先 ...

  7. 使用Scala编写Spark程序求基站下移动用户停留时长TopN

    使用Scala编写Spark程序求基站下移动用户停留时长TopN 1. 需求:根据手机基站日志计算停留时长的TopN 我们的手机之所以能够实现移动通信,是因为在全国各地有许许多多的基站,只要手机一开机 ...

  8. SEO的5大关键指标:排名+流量+会话+停留时长+跳出率

    从搜索引擎获取流量,是每家企业的共识,但怎样能够获得更多更高质量更持久的免费流量呢?答案是搜索引擎优化,即SEO. 一份好的SEO报告可以反映出企业当前状态以及未来的发展趋势.SEO报告上的数据,可以 ...

  9. IJCAI阿里论文 | JUMP: 一种点击和停留时长的协同预估器...

    小叽导读:在搜索和推荐场景中,基于会话的预测日益受到人们的兴趣和重视,大多这类算法都是基于递归神经网络(RNNs)技术或者它的变种.然而,已有的算法一方面会忽略"停留时长"在表达用 ...

最新文章

  1. 17委托异步调用方法
  2. python创建txt文件-python创建txt文件
  3. boost::sort模块实现spreadsort 字符串函子排序示例
  4. Python学习:numpy的使用技巧和注意
  5. nafxcw.lib与LIBCMT.lib在vs2008中链接冲突解决方案
  6. Apache网站服务
  7. 电子数字 网易游戏在线笔试 第一题 hihocoder
  8. vba 修改文本文档 指定行_再说For Each循环——无论Python还是VBA都要看
  9. python远程执行linux命令unzip_Linux unzip命令
  10. linux交叉编译libnet,交叉编译samba(mipsel-linux) samba-3.3.3.tar.gz
  11. python如何计算等额本息还款_银行等额本息还款算法
  12. matlab 解决列联表问题,列联表那点事,别再傻傻分不清楚了
  13. NKOJ 4234 三角分形
  14. Kali学习 | 漏洞扫描:3.1 Nessus安装、配置和新建扫描任务
  15. 关于有道云笔记偶尔会抽风变换语言这回事
  16. Android 简历+面试题 汇总
  17. tableau 字段去重_tableau prep学习
  18. 【Delphi】中使用消息Messages(八)Android 系统消息感知
  19. 分享:ThinkPad E40无线网卡驱动安装 FOR CENTOS6.3
  20. 4242. 货币兑换

热门文章

  1. 在网页标题栏加入图标
  2. 24小时内最快跑完最详细BSC全节点搭建同步实战
  3. KubeSphere部署WordPress
  4. python爬取街拍美女图片
  5. L1-033 出生年 (15分)
  6. 在服务器上用sendmail代发邮件
  7. 微擎后台数据库表关系
  8. P5397 天降之物
  9. Ubuntu系统下配置Apache虚拟主机
  10. 便宜哭!戴尔官网竟然可以在线砍价直降3270,比双11还超值!