彻底掌握页面白屏检测

前言

在日常的前端开发中,白屏几乎是每个前端开发者都会遇到的问题。白屏问题严重影响了用户体验。当用户访问一个页面时,如果页面长时间处于白屏状态,用户可能会认为页面出现了问题,从而选择离开。这对于任何一个网站都是不利的,尤其是对于那些依赖用户流量的电商网站来说,白屏问题可能直接导致用户流失和收入下降。

许多研究都表明,用户最满意的打开网页时间,是在2秒以下。 用户能够忍受的最长等待时间的中位数,在6~8秒之间。 这就是说,8秒是一个临界值,如果你的网站打开速度在8秒以上,那么很可能,大部分访问者最终都会离你而去。

白屏的主要原因

白屏的主要原因可以从浏览器渲染的整个流程来分析,我们知道从一次请求到页面渲染大致会经过以下过程

用户输入URL -> DNS解析 -> 建立连接 -> 返回内容 -> 浏览器解析响应内容 -> 浏览器渲染

其中任何一环出现问题都有可能造成页面白屏,下面是一些最常见的白屏原因:

1. 资源加载失败页面依赖的关键资源(CSS、JS、图片等)加载失败,导致页面无法正常渲染。
//例如我们在React项目中引入了不存在的js资源或者资源加载失败,就会造成页面无法正常渲染,导致白屏。
import './index.js'
function App() {return (<div className="App">app</div>)
}
export default App

这种情况下我们可以在关键的接口和请求上增加响应监控。

2. 资源加载延迟资源加载延迟(或阻塞),导致页面长时间等待资源加载完成。出现空白。
//例如我们在这里,App 组件在挂载后会使用 setTimeout 模拟资源加载延迟 8 秒。  
import { useState, useEffect } from 'react'
import Preview from 'preview'
function App() {const [data, setData] = useState(null)useEffect(() => {setTimeout(() => {setData({ name: 'test' })}, 10000)  // 模拟资源加载 10000 秒}, [])return (<div className="App">{data && <Preview />}</div>)
}
export default App

这种情况可以前端做一些loading状态或者增加骨架屏,防止页面无内容造成用户困扰。

3. 代码执行中出现未被捕捉的错误,例如JavaScript执行错误,Promise错误等等。导致页面功能无法正常工作,出现空白。

这个错误也是前端最最最常见的一个错误,如果没有处理好异常情况导致抛出错误有没有被捕获,就会造成页面崩溃。

function App() {return (<div className="App">{JSON.parse(data.name) // 未对data.name判空导致parse解析失败}</div>)
}
export default App
4. 浏览器兼容问题

不同的浏览器对于前端技术的支持程度不同,如果我们使用了浏览器不支持的语法或者CSS类型,可能导致某些浏览器无法正常显示页面。

function App() {return (<div className="App">{data?.name} // 例如浏览器不支持可选链式符就会报错, https://caniuse.com/?search=%3F.</div>)
}
export default App

除此之外,第三方服务或资源出现问题,浏览器缓存、CDN问题等也会导致页面白屏的问题。在实际开发中我们需要考虑到各种可能的情况逐步排查。

如何监测页面白屏

要检测白屏,主线的思路就是检测在特定时间特定的DOM是否存在于页面中。或者是通过页面截图并且识别图片是否包含内容等方式(代价太高)。下面就给大家分享几种常用的方式,最后也会给出一种最通用的方式。

1. 全局错误监听 + 判断对应节点是否存在

例如在React中我们可以使用ErrorBoundary实现由于代码执行错误导致白屏的检测步骤:

  1. 首先,创建一个名为 ErrorBoundary 的新组件。在这个组件中,我们需要定义一个名为 componentDidCatch 的生命周期方法,它将在子组件中捕获到错误时被调用。同时,我们需要在组件的状态中存储一个表示是否发生错误的变量。
import React, { Component } from 'react';class ErrorBoundary extends Component {constructor(props) {super(props);this.state = { hasError: false };}componentDidCatch(error, info) {// 在这里可以将错误记录到日志,或者发送给后端console.log(error, info);this.setState({ hasError: true });if (!document.getElementById('container').innerHTML) {console.log('页面白屏了');}}render() {// if (this.state.hasError) {//   // 如果发生错误,显示备用 UI//   return <h1>出错了,请刷新页面或联系客服。</h1>;// }// 如果没有发生错误,正常渲染子组件return this.props.children;}
}export default ErrorBoundary;
  1. 接下来,将 ErrorBoundary 组件包裹在应用程序的根组件中,以便捕获整个应用程序的错误。
const App = () => {return <div>{a?.sjakd}</div>
}import React from 'react';
import ReactDOM from 'react-dom';
import ErrorBoundary from './ErrorBoundary';ReactDOM.render(<React.StrictMode><ErrorBoundary><App /></ErrorBoundary></React.StrictMode>,document.getElementById('root')
);

现在,如果应用程序中的任何子组件发生错误,ErrorBoundary 组件将捕获该错误,并判断对应的根节点是否函数对应的节点来实现白屏检测。

2. Mutation Observer 监听 DOM 变化

MutationObserver API 可以用于监测DOM树的变化。我们可以通过MutationObserver来监测页面的DOM变化,从而判断页面是否出现白屏现象。

class App extends React.Component {componentDidMount() {const observer = new MutationObserver((mutations, observer) => {const duration = Date.now() - observer.startTime;if (duration > 3000) {console.log('页面白屏时间超过3秒');}});observer.startTime = Date.now();observer.observe(document.body, { childList: true, subtree: true });}// ...
}

以React框架为例,我们可以在componentDidMount生命周期函数中使用MutationObserver API 获取相关信息。如果两次渲染时间过长说明出现了白屏的情况。

但是这种方法对下面这两种情况没有很好的解决办法

1)DOM根本就没有渲染

2)遇到有骨架屏的项目,若页面从始至终就没变化,一直显示骨架屏,这种情况 Mutation Observer 也束手无策

3. 关键点采样对比

所谓关键点采样就是在我们的屏幕中,随机取几个固定的点,利用document.elementsFromPoint(x,y)该函数返还在特定坐标点下的 HTML 元素数组。这也是准确率比较高的一种做法,目前主流的都是这种检测方法。具体实现如下:

1、页面中间取n个采样点,利用 elementsFromPoint api 获取该坐标点下的 HTML 元素。采样方法有垂直选取交叉选取,以及垂直交叉选取三种方法,对应的采样图片如下:

image-20240703153111902 image-20240703153128412 image-20240703153150175

2、定义属于容器元素的集合,如 ['html', 'body', '#app', '#root']

3、判断这n个采样点是否在该容器集合中。目的就是为了判断采样点有没有内容;如果没有内容,那么我们获取到的 dom 元素就是容器元素,若n个采样点都没有内容则可判定为白屏

4、若初次判断是白屏,开启轮询检测,来确保白屏检测结果的正确性,直到页面的正常渲染或者重试一定次数就关闭定时器

具体代码实现如下

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<script>function whiteScreenMonitor(wrapperSelectors) {// 记录空白点数let emptyPoints = 0;let timer = null;const maxRetryTime = 5;let retryTime = 0;// 获取元素的选择器function getSelector(element) {if (element?.id) {return `#${element.id}`;} if (element?.className) {return (`.${element.className.split(' ').filter(item => !!item).join('.')}`);}return element?.nodeName.toLowerCase();}// 判断元素是否为包裹元素function isWrapper(element) {const selector = getSelector(element);if (wrapperSelectors.indexOf(selector) !== -1) {return true;}}function checkBlankScreen() {// 检查屏幕的点,分别为横向和纵向的点for (let i = 1; i <= 9; i++) {// 获取当前点的所有元素const xElements = document.elementsFromPoint((window.innerWidth * i) / 10,window.innerHeight / 2,);const yElements = document.elementsFromPoint(window.innerWidth / 2,(window.innerHeight * i) / 10,);// 取第一个来判断emptyPoints += !!isWrapper(xElements[0]);emptyPoints += !!isWrapper(yElements[0]);}// 如果空白点数超过16个,表示屏幕为空白if (emptyPoints > 16) {console.log(`这是第 ${retryTime} 次检测,页面白屏了`);if (++retryTime > maxRetryTime) {console.log('页面白屏检测超过最大次数,可判定为白屏');// 这里可以做一些监控上报之类的事情clearTimeout(timer);return;}if (!timer) {timer = setInterval(() => {emptyPoints = 0;checkBlankScreen();}, 1000);}} else {clearTimeout(timer);}}window.addEventListener('load', checkBlankScreen);
}// 开始检测白屏,如果是SDK则可以将这个当法导出
whiteScreenMonitor(['html', 'body', '#container', '.content', '#app', '#root']);
</script>
<body>
<div id="root"></div>
</body>
<script>setTimeout(() => {const content = document.createElement('div')content.style.width = '500px'content.style.height = '500px'content.style.backgroundColor = 'red'document.getElementById('root').appendChild(content) // 挂载}, 10000); // 模拟白屏的操作
</script>
</html>

这里使用初次检测 + 轮训防止误判的方式来进行白屏检测。关键内容在函数checkBlankScreen中取点并判断内容是容器节点的个数。

image-20240703155810525

使用了骨架屏的页面如何检测白屏

对于有骨架屏的页面,用户打开页面后,先看到骨架屏,然后再显示正常的页面,来提升用户体验;但如果页面从始至终都显示骨架屏,也算是白屏的一种

骨架屏示例:https://ant-design.antgroup.com/components/skeleton-cn

检测骨架屏的白屏的方式其实也很简单,我们可以稍微改改上面的方法即可:

  1. 传入骨架屏对应的容器给whiteScreenMonitor函数,这样检测的时候就可以将骨架屏的内容过滤掉。
  2. 改变检测白屏的方式,我们通过每次获取到的内容和第一次获取到的内容进行对比,如果每一次都相同说明是白屏的。但是这里就需要保证我们的白屏检测代码一定要是最先运行的,不然等我们所有的内容都渲染完了再检测,这是后内容也是没有改变的。

总结

以上就是常用的白屏检测方法了,相信看完大家以后对于如何检测项目中白屏有了自己的看法。

最后打个广告,我新开了个公众号,旨在将自己日常学习的内容进行沉淀。这个公众号会经常更新前端相关的技术文章,还请大家多多支持,点点关注💗。

image-20240703162104337

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/865418.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python成为全球热门语言的“秘密”

1994年&#xff0c;美国举办了一次 针对Python的workshop 从全美国选出来的程序员 聚在一起讨论着这个“秘密武器” Python是如何从一个开发者的“副业” 变成现在全球热门语言呢&#xff1f; 今天我们一起探讨一下Python简史 往下翻看&#xff0c;解锁答案&#x1f447…

iOS 视图实现渐变色背景

需求 目的是要实现视图的自定义的渐变背景色&#xff0c;实现一个能够随时使用的工具。 实现讨论 在 iOS 中&#xff0c;如果设置视图单一的背景色&#xff0c;是很简单的。可是&#xff0c;如果要设置渐变的背景色&#xff0c;该怎么实现呢&#xff1f;其实也没有很是麻烦&…

MSI安装包安装的Mysql8,配置文件my.ini在哪儿?

版本 我安装的版本是8.0.36&#xff0c;server根目录下没有配置文件。 文件位置 首先找到对应的windows服务 右击属性&#xff0c;可以看到启动参数&#xff0c;启动参数中有配置文件的路径 比如我的配置文件在"C:\ProgramData\MySQL\MySQL Server 8.0\my.ini"

Pylons 和 Flex 3

“Pylons” 和 “Flex 3” 是两个不同的技术&#xff0c;各自有着不同的背景和应用场景&#xff1a; Pylons Pylons 是一个 Python Web 框架&#xff0c;用于快速开发 Web 应用程序。它强调简单性、灵活性和可扩展性&#xff0c;以便开发人员能够快速构建和部署功能强大的 We…

mysql数据库自动备份

crond cron 实现定时执行 安装 yum install crond启动 service crond start查看状态 service crond status执行 crontab xx.cron查看任务列表 crontab -l删除所有任务 crontab -r 示例&#xff1a;每分钟写入 Good morning 到 mine.cron [rootecs-f1dd-0001 fztmp]# echo ‘* …

【CUDA】 归约 Reduction

Reduction Reduction算法从一组数值中产生单个数值。这个单个数值可以是所有元素中的总和、最大值、最小值等。 图1展示了一个求和Reduction的例子。 图1 线程层次结构 在Reduction算法中&#xff0c;线程的常见组织方式是为每个元素使用一个线程。下面将展示利用许多不同方…

反射快速入门

反射就是通过字节码文件获取类的成员变量、构造方法和成员方法的所有信息。 利用反射&#xff0c;我们可以获取成员变量的修饰符、名字、类型、取值。我们可以获取构造方法的名字、形参&#xff0c;并利用通过反射获取的构造方法创建对象。我们可以获取成员方法的修饰符、名字、…

主食冻干复查|希喂、喜崽、生生不息可以盲选吗?测评结果来揭秘

在挑选主食冻干时&#xff0c;许多宠物主人都会感到头疼。尽管主食冻干相较于普通猫粮具有诸多优势&#xff0c;但其价格也相对高昂。这导致许多宠物主人担心高价购买的主食冻干可能营养价值并不理想。然而&#xff0c;在选择时&#xff0c;我们还需要考虑其他重要因素&#xf…

Zabbix 配置PING监控

Zabbix PING监控介绍 如果需要判断机房的网络或者主机是否正常&#xff0c;这就需要使用zabbix ping&#xff0c;Zabbix使用外部命令fping处理ICMP ping的请求&#xff0c;在基于ubuntu APT方式安装zabbix后默认已存在fping程序。另外zabinx_server配置文件参数FpingLocation默…

【C++】多态(详解)

前言&#xff1a;今天学习的内容可能是近段时间最难的一个部分的内容了&#xff0c;C的多态&#xff0c;这部分内容博主认为难度比较大&#xff0c;各位一起慢慢啃下来。 &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; 专栏分类:高质量&#xff23…

操作系统真象还原:编写硬盘驱动程序

第13章-编写硬盘驱动程序 这是一个网站有所有小节的代码实现&#xff0c;同时也包含了Bochs等文件 13.1 硬盘及分区表 13.1.1 创建从盘及获取安装的磁盘数 要实现文件系统&#xff0c;必须先有个磁盘介质&#xff0c;虽然咱们己经有个虚拟磁盘 hd60M.img&#xff0c;但它只…

力扣67 二进制求和

文章目录 1. 题目链接2. 题目代码3.感受 1. 题目链接 二进制求和 2. 题目代码 class Solution { public:string addBinary(string a, string b) {vector<int> stringA;vector<int> stringB;int lengthOfA a.length();int lengthOfB b.length();for(int subscrip…

OceanBase Meetup北京站|跨行业应用场景中的一体化分布式数据库:AI赋能下的探索与实践

随着业务规模的不断扩张和数据处理需求的日益复杂化&#xff0c;传统数据库架构逐渐暴露出业务稳定性波动、扩展性受限、处理效率降低以及运营成本高等一系列问题。众多行业及其业务场景纷纷踏上了数据库现代化升级之路。 为应对这些挑战&#xff0c;7月6日&#xff0c;OceanB…

专注于文件夹加密和保护的免费软件

一、简介 1、这是一款专注于文件夹加密和保护的免费软件。允许用户为重要的文件或文件夹设置密码&#xff0c;从而防止未经授权的访问。软件提供了隐藏、锁定、只读等多种保护模式&#xff0c;用户可以根据需要选择适合的模式来保护文件。除了基本的加密功能外&#xff0c;它还…

【java计算机毕设】陪诊师管理系统java MySQL springboot vue3 Maven源码 代码+文档PPT

目录 1项目功能 2项目介绍 3项目地址 1项目功能 【java计算机毕设】陪诊师管理系统java MySQL springboot vue3 Maven项目设计源码代码万字文档ppt 2项目介绍 系统功能&#xff1a; vue3陪诊师管理系统。 该平台采用了前后端分离技术&#xff0c;SpringBoot和VUE3框架&…

告别熬夜改稿:AI降重工具让论文降重变得轻松又有趣

已经天临五年了&#xff0c;大学生们还在为论文降重烦恼……手动降重确实是个难题&#xff0c;必须要先付点小经费去靠谱的网站查重&#xff0c;再对着红字标注去改&#xff0c;后面每一次的论文呢查重结果都像赌//博&#xff0c;谁也不知道明明是同一篇文章&#xff0c;第二次…

Halcon 曲线追踪

Halcon 曲线追踪&#xff08;边缘检测、xld分割、xld筛选、线段合并&#xff09; 图片数据与程序 链接&#xff1a;https://pan.baidu.com/s/1feGOa0A7dvCeBjQivr6TvA 提取码&#xff1a;f2ws 原图 起点终点方向 * 1.加载图片 ********************************************…

Python处理异常用操作介绍

Python中的异常处理主要用于捕获和处理程序运行过程中出现的错误。 在编写Python程序时&#xff0c;我们经常会遇到各种错误&#xff0c;如语法错误、运行时错误等。为了确保程序的稳定性和健壮性&#xff0c;我们需要对可能出现的错误进行捕获和处理。本文将介绍Python中常用的…

[笔记] 卷积 - 02 滤波器在时域的等效形式

1.讨论 这里主要对时域和频域的卷积运算的特征做了讨论&#xff0c;特别是狄拉克函数的物理意义。 关于狄拉克函数&#xff0c;参考这个帖子&#xff1a;https://zhuanlan.zhihu.com/p/345809392 1.狄拉克函数提到的好函数的基本特征是能够快速衰减&#xff0c;对吧&#xf…

软件功能测试基础知识大揭秘,功能测试报告就找专业软件测评机构

软件功能测试是以软件产品的需求规格为基础&#xff0c;通过对软件功能的逐个测试&#xff0c;验证软件是否符合需求规格&#xff0c;是否能够正常执行各项功能操作。对于软件产品而言&#xff0c;功能测试是一项至关重要的工作&#xff0c;它能够发现软件中存在的功能缺陷、错…