web用户停留时长

1,061 阅读3分钟

页面停留时间(Time on Page) 代码:github.com/fanxinqi/mm…

简称 TP 是分析用户粘性的重要指标之一 停留时长也可以侧面反映出网站的用户体验。平均访问时长越短,说明网站对用户的吸引力越差。

主流的数据分析工具

Google Analytics、WebTrends、Omniture、百度分析、CNZZ中都有计算。

计算规则

页面的停留时长 = 进入下一个页面的时间 - 进入本页面的时间- 不活跃时间。 pageonsite(time)=nextpage(time)currentpage(timeunactivetimepage on site (time) = next page(time) - current page(time)- unactive(time) image.png page(△t) = (t1-t0) + (t2-t3)+ .... +(tn-tn-1)

web应用类型路由类型

目前web应用主流的路由方式

  • 多页面路由应用(传统web方式)
  • history路由 单页面应用
  • hash路由 单页面应用

浏览器行为事件

image.png

统计行为map

image.png

存储方案

可以使用 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()  方法会使用户代理在有机会时异步地向服务器发送数据,同时不会延迟页面的卸载或影响下一导航的载入性能,这意味着:

  • 数据发送是可靠的。
  • 数据异步传输。
  • 不影响下一导航的载入。

完整代码:github.com/fanxinqi/mm…