Webfunny白屏检测方案

一步一个脚印一个坑 6月前 ⋅ 1345 阅读
ad

Hello,大家好,欢迎使用Webfunny前端监控和埋点系统。

经过了半个月的努力,我们终于上线了白屏检测和采集的能力。通过webfunny探针对前端页面进行白屏检测,并截图上报,让我们可以快速的定位白屏问题。

今天,我们将介绍webfunny如何判断页面白屏状态,以及如何通过技术手段定位白屏问题。

一、为什么需要检测白屏

白屏是最严重的生产事故之一,如果大量发生,将直接导致业务瘫痪。页面白屏,绝对是让前端开发者最为胆寒的事情,特别是随着 SPA 项目的盛行,前端白屏的情况变得更为复杂且棘手起来。

复现难度高,面对这样的问题,内心很虚,因为导致白屏出现的原因非常多,这不是一个明确的错误,如果没有好用的监控工具,真不知道该从何入手。

二、分析有哪些情况下会产生白屏

想要检测白屏就需要先分析会产生白屏的场景,然后对症下药。

第一种:页面加载期间,js代码报错,直接导致白屏;这种白屏常见于开发阶段,也最容易被发现的,一般情况下不会被带到生产环境。

第二种:静态资源加载失败,关键js文件无法被引入,导致白屏;为了让页面加载更快,大部分公司都会选择将静态资源文件上传到自己的CDN服务器或者第三方CDN服务器,如果CDN服务器出现波动,就会导致白屏产生。

第三种:接口无法返回正常结果,或者返回空结果,导致页面无法渲染数据,出现白屏、缺省屏或骨架屏等;缺省状态和骨架屏从某种意义上看也是属于业务白屏的一种。

第四种:页面本来是好好的,但是点击按钮后,出现报错,导致页面白屏,这种情况是不易发现的,白屏效果跟第一种是相同的。

以上四种基本概括了线上可能会出现白屏的场景,知道了发生的场景,下边我们来看看如何进行检测吧。

三、白屏检测方案有哪些

方法1:检查DOM根节点是否有内容;

原理很简单,在当前主流的三大框架中,DOM 一般都会挂载在一个根节点之下(比如 <div id="app"></div> ),发生白屏后通常是根节点下所有 DOM 被卸载,该方法通过检测根节点下是否挂载 DOM,若无则证明白屏

这是一种简单明了且有效的方案,但缺点也很明显:其一切建立在 白屏 === 根节点下 DOM 被卸载 成立的前提下,缺点是通用性较差,对于有骨架屏的情况束手无策。

方法2:Mutation Observer 监听 DOM 变化;

通过此MutationObserver.MutationObserver API 监听页面 DOM 变化,每当被指定的节点或子树以及配置项有 DOM 变动时都可以监听到

function callback(mutationList, observer) {
  mutationList.forEach((mutation) => {
    switch (mutation.type) {
      case "childList":
        /* 从树上添加或移除一个或更多的子节点;参见 mutation.addedNodes 与
           mutation.removedNodes */
        break;
      case "attributes":
        /* mutation.target 中某节点的一个属性值被更改;该属性名称在 mutation.attributeName 中,
           该属性之前的值为 mutation.oldValue */
        break;
    }
  });
}

但这个方法有两个问题:

1)白屏不一定是 DOM 被卸载,也有可能是压根没渲染,比如js代码报错,刚进来就是白屏的,

2)遇到有骨架屏的项目,若页面从始至终就没变化,一直显示骨架屏,这种情况 Mutation Observer 也无法做到准确判断

方法3:页面截图检测

首先对页面进行截图,将截图与一张纯白的图片做对比,判断两者是否足够相似,或者根据图片截图的大小来判断。

但这个方案有两个缺陷:

1、方案较为复杂,性能不高;一方面需要借助 canvas 实现前端截屏,同时需要借助复杂的算法对图片进行对比

2、通用性较差,对于有骨架屏或者有占位符的项目,对比的效果就会出现明显的差异

方法4:对页面采样判断

采样对比+白屏修正机制是目前比较主流的方式,利用 elementsFromPoint api 获取该坐标点下的 HTML 元素

1、页面中间取17个采样点(如下图)。

2、判断17这个采样点是否在该容器集合中,就是判断这17个位置下有没有dom元素,如果都没有,则说明白屏了,同时开启轮询检测,来确保白屏检测结果的正确性,直到页面的正常渲染。

采样点分布图(蓝色为采样点):

方法5:采样对比 + DOM数量平均值判断

采样对比加修正也需要循环判断,比较消耗性能。从真正解决问题的角度来看,如果一直是占位符或者骨架屏,那么也属于业务白屏了,这种方式就不行了。

通过采集每个页面正常状态下的dom数量,从而得到平均值。依据平均值,可以通过DOM数量来辅助判断白屏和业务白屏的方式,提升白屏判断的准确性。

// 定义外层容器元素的集合
 const containerElements = ['html', 'body', '#app', '#root'];

// 选中dom的名称
export const getSelector = (element) => {
  if (element.id) {
    return "#" + element.id;
  } else if (element.className) {// div home => div.home
    return "." + element.className.split(' ').filter(item => !!item).join('.');
  } else {
    return element.nodeName.toLowerCase();
  }
}

// 是否为容器节点,如果是容器,则是白点
// true: 白点, false: 非白点
export const isContainer = (element) => {
  let selector = getSelector(element);
  if (containerElements.indexOf(selector) != -1) {
    return true
  }
  return false
}

// 判断是否白屏
export const chargeWhiteScreen = () => {
  let isWhiteScreen = true
  // 页面加载完毕初始化
  for (let i = 1; i <= 9; i++) {
    let xElements = document.elementsFromPoint(window.innerWidth * i / 10, window.innerHeight / 2);
    let yElements = document.elementsFromPoint(window.innerWidth / 2, window.innerHeight * i / 10);
    if (!isContainer(xElements[0])) {
      isWhiteScreen = false
      break
    }
    if (!isContainer(yElements[0])) {
      isWhiteScreen = false
      break
    }
  }
  return isWhiteScreen
}
// Dom总数量
const domNodeCount = document.querySelector("body").getElementsByTagName('*').length

四、验证白屏检测效果

通过用户细查,可以将用户产生白屏的过程记录下来,代码报错或者接口报错导致白屏,最后截图上报。

我们将白屏分为:极可能白屏、疑似白屏两种情况;极可能白屏代表完全看不到元素的白屏,疑似白屏代表骨架屏或者占位符的页面。

如图所示,验证成功!

好了,关于webfunny的白屏检测方案已经介绍完了,如果有什么问题,请联系我吧。

 

参考文档: https://juejin.cn/post/7176206226903007292

关于Webfunny

Webfunny专注于前端监控系统,前端埋点系统的研发。 致力于帮助开发者快速定位问题,帮助企业用数据驱动业务,实现业务数据的快速增长。支持H5/Web/PC前端、微信小程序、支付宝小程序、UniApp和Taro等跨平台框架。实时监控前端网页、前端数据分析、错误统计分析监控和BUG预警,第一时间报警,快速修复BUG!支持私有化部署,Docker容器化部署,可支持千万级PV的日活量!

  点赞 0   收藏 0
  • 一步一个脚印一个坑
    共发布127篇文章 获得4个收藏
全部评论: 0