页面停留时间(Time on Page) 代码:github.com/fanxinqi/mm…
简称 TP 是分析用户粘性的重要指标之一 停留时长也可以侧面反映出网站的用户体验。平均访问时长越短,说明网站对用户的吸引力越差。
主流的数据分析工具
Google Analytics、WebTrends、Omniture、百度分析、CNZZ中都有计算。
计算规则
页面的停留时长 = 进入下一个页面的时间 - 进入本页面的时间- 不活跃时间。
page(△t) = (t1-t0) + (t2-t3)+ .... +(tn-tn-1)
web应用类型路由类型
目前web应用主流的路由方式
- 多页面路由应用(传统web方式)
- history路由 单页面应用
- hash路由 单页面应用
浏览器行为事件
统计行为map
存储方案
可以使用 Window.sessionStorage
:主要目的为了防止浏览器关闭等异常情况,数据没有发送成功的情况,可以在下次访问页面先看缓存中是否有记录,优先发送遗留记录
代码实现
history 路由
使用 back()
, forward()
和 go()
方法来完成在用户历史记录中向后和向前的跳转
路由变化相应事件
popstate
// 浏览器前进后退
window.addEventListener("popstate", (e) => {
this.updateView(window.location.pathname);
});
window.addEventListener("load", () => this.updateView("/"), false);
}
history 路由停留时长监控问题
单页面路由实现重点,就是监控路由的变化: HTML5 引入了 history.pushState() 和 history.replaceState() 方法,它们分别可以添加和修改历史记录条目,但这两个api 并不会处罚popstate 事件 隐藏需要劫持这两个原生api 进行处理
monkey patch(猴子补丁)
猴子布丁:猴子补丁的叫法有些莫名其妙,只要和“模块运行时替换的功能”对应就行了
history monkey patch 实现
/*
* history monkey patch
*/
export const rewriteHistroy = function (type: string) {
let routerApi = (window as any).history[type];
return function () {
let result = routerApi.apply(this, arguments);
let e = new Event(type.toLowerCase());
(e as any).arguments = arguments;
window.dispatchEvent(e);
return result;
};
};
这样 在调用pushstate 和repalcestate 就会dispatch 同名事件,在这个事件中可以做这两个api操作的路由变化监控
private initHistoryEvent(): void {
window.history.pushState = rewriteHistroy("pushState");
window.history.replaceState = rewriteHistroy("replaceState");
window.addEventListener("popstate", () => {
this.setPageChangeState();
});
window.addEventListener("pushstate", () => {
this.setPageChangeState();
});
window.addEventListener("replacestate", () => {
this.setPageChangeState();
});
}
hash 路由 没啥特别之处
路由变化都会触发 popstate
window.addEventListener("popstate", () => {
this.setPageChangeState();
});
多页面应用事件监控
// 页面显示
window.addEventListener("pageshow", () => {
this.startTime = new Date().getTime();
this.setCurrentUniqueName();
Store.update(this.uniqueName, {
startTime: this.startTime,
location: window.location,
});
});
// 页面即将离开
window.addEventListener("beforeunload", () => {
// 在隐藏状态下直接关闭页面,要记录
if (this.unActionStartTime > 0) {
this.unActiveDuration = new Date().getTime() -this.unActionStartTime;
}
this.setPageChangeState();
});
发送逻辑
Navigator.sendBeacon()
navigator.sendBeacon()
方法可用于通过 HTTP POST 将少量数据异步传输到 Web 服务器。
它主要用于将统计数据发送到 Web 服务器,同时避免了用传统技术(如:XMLHttpRequest
)发送分析数据的一些问题。
当用户代理成功把数据加入传输队列时,sendBeacon()
方法将会返回 true
,否则返回 false
。
描述
这个方法主要用于满足统计和诊断代码的需要,这些代码通常尝试在卸载(unload)文档之前向web服务器发送数据。过早的发送数据可能导致错过收集数据的机会。然而,对于开发者来说保证在文档卸载期间发送数据一直是一个困难。因为用户代理通常会忽略在 unload (en-US)
事件处理器中产生的异步 XMLHttpRequest
。
过去,为了解决这个问题, 统计和诊断代码通常要在
- 发起一个同步
XMLHttpRequest
来发送数据。 - 创建一个
<img>
元素并设置src
,大部分用户代理会延迟卸载(unload)文档以加载图像。 - 创建一个几秒的 no-op 循环。
上述的所有方法都会迫使用户代理延迟卸载文档,并使得下一个导航出现的更晚。下一个页面对于这种较差的载入表现无能为力。
这就是 sendBeacon()
方法存在的意义。使用 sendBeacon()
方法会使用户代理在有机会时异步地向服务器发送数据,同时不会延迟页面的卸载或影响下一导航的载入性能,这意味着:
- 数据发送是可靠的。
- 数据异步传输。
- 不影响下一导航的载入。