前端白屏的检测方案,让你知道自己的页面白了 |
您所在的位置:网站首页 › 脚本加载不了咋办 › 前端白屏的检测方案,让你知道自己的页面白了 |
前言
页面白屏,绝对是让前端开发者最为胆寒的事情,特别是随着 SPA 项目的盛行,前端白屏的情况变得更为复杂且棘手起来( 这里的白屏是指页面一直处于白屏状态 ) 要是能检测到页面白屏就太棒了,开发者谁都不想成为最后一个知道自己页面白的人😥 web-see 前端监控方案,提供了 采样对比+白屏修正机制 的检测方案,兼容有骨架屏、无骨架屏这两种情况,来解决开发者的白屏之忧 知道页面白了,然后呢?web-see 前端监控,会给每次页面访问生成一个唯一的uuid,当上报页面白屏后,开发者可以根据白屏的uuid,去监控后台查询该id下对应的代码报错、资源报错等信息,定位到具体的源码,帮助开发者快速解决白屏问题 白屏检测方案的实现流程采样对比+白屏修正机制的主要流程: 1、页面中间取17个采样点(如下图),利用 elementsFromPoint api 获取该坐标点下的 HTML 元素 2、定义属于容器元素的集合,如 [‘html’, ‘body’, ‘#app’, ‘#root’] 3、判断17这个采样点是否在该容器集合中。说白了,就是判断采样点有没有内容;如果没有内容,该点的 dom 元素还是容器元素,若17个采样点都没有内容则算作白屏 4、若初次判断是白屏,开启轮询检测,来确保白屏检测结果的正确性,直到页面的正常渲染 采样点分布图(蓝色为采样点): 下面聊一聊具体的分析与实现 白屏检测的难点1) 白屏原因的不确定 从问题推导现象虽然能成功,但从现象去推导问题却走不通。白屏发生时,无法和具体某个报错联系起来,也可能根本没有报错,比如关键资源还没有加载完成 导致白屏的原因,大致分两种:资源加载错误、代码执行错误 2) 前端渲染方式的多样性 前端页面渲染方式有多种,比如 客户端渲染 CSR 、服务端渲染 SSR 、静态页面生成 SSG 等,每种模式各不相同,白屏发生的情况也不尽相同 很难用一种统一的标准去判断页面是否白了 技术方案调研如何设计出一种,在准确性、通用型、易用性等方面均表现良好的检测方案呢? 本文主要讨论 SPA 项目的白屏检测方案,包括有无骨架屏的两种情况 方案一:检测根节点是否渲染 原理很简单,在当前主流 SPA 框架下,DOM 一般挂载在一个根节点之下(比如 ),发生白屏后通常是根节点下所有 DOM 被卸载,该方法通过检测根节点下是否挂载 DOM,若无则证明白屏 这是简单明了且有效的方案,但缺点也很明显:其一切建立在 白屏 === 根节点下 DOM 被卸载 成立的前提下,缺点是通用性较差,对于有骨架屏的情况束手无策 方案二:Mutation Observer 监听 DOM 变化 通过此 API 监听页面 DOM 变化,并告诉我们每次变化的 DOM 是被增加还是删除 但这个方案有几个缺陷 1)白屏不一定是 DOM 被卸载,也有可能是压根没渲染,且正常情况也有可能大量 DOM 被卸载 2)遇到有骨架屏的项目,若页面从始至终就没变化,一直显示骨架屏,这种情况 Mutation Observer 也束手无策 方案三:页面截图检测 这种方式是基于原生图片对比算法处理白屏检测的 web 实现 整体流程:对页面进行截图,将截图与一张纯白的图片做对比,判断两者是否足够相似 但这个方案有几个缺陷: 1、方案较为复杂,性能不高;一方面需要借助 canvas 实现前端截屏,同时需要借助复杂的算法对图片进行对比 2、通用性较差,对于有骨架屏的项目,对比的样张要由纯白的图片替换成骨架屏的截图 方案四:采样对比 该方法是对页面取关键点,进行采样对比,在准确性、易用性等方面均表现良好,也是最终采用的方案 对于有骨架屏的项目,通过对比前后获取的 dom 元素是否一致,来判断页面是否变化(这块后面专门讲解) 采样对比代码: // 监听页面白屏 function whiteScreen() { // 页面加载完毕 function onload(callback) { if (document.readyState === 'complete') { callback(); } else { window.addEventListener('load', callback); } } // 定义外层容器元素的集合 let containerElements = ['html', 'body', '#app', '#root']; // 容器元素个数 let emptyPoints = 0; // 选中dom的名称 function 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(); } } // 是否为容器节点 function isContainer(element) { let selector = getSelector(element); if (containerElements.indexOf(selector) != -1) { emptyPoints++; } } onload(() => { // 页面加载完毕初始化 for (let i = 1; i { sampling() }, 1000) } 骨架屏对于有骨架屏的页面,用户打开页面后,先看到骨架屏,然后再显示正常的页面,来提升用户体验;但如果页面从始至终都显示骨架屏,也算是白屏的一种 骨架屏示例: 有骨架屏的html文件: 如果不通过外部传参,SDK 能否自己判断是否有骨架屏呢? 比如在页面初始的时候,根据根节点上有没有子节点来判断 因为这套检测方案需要兼容 SSR 服务端渲染的项目,对于 SSR 项目来说,浏览器获取 html 文件的根节点上已经有了 dom 元素,所以最终采用外部传参的方式来区分 总结这套白屏检测方案是从现象推导本质,可以覆盖绝大多数 SPA 项目的应用场景 小伙们若有其他检测方案,欢迎多多讨论与交流 💕 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |