欢迎来到我的博客文章!所有文章都是满满的前端干货,文章简明扼要。
一句话总结:白屏检测没有"银弹",生产环境通常采用 "DOM 节点检查 + 关键像素采样 + 错误监控"组合拳。
| 方案 | 原理 | 准确率 | 性能消耗 | 适用场景 |
|---|---|---|---|---|
| 1. DOM 节点检测 | 检查根节点是否有内容 | ⭐⭐⭐⭐ | 低 | 最推荐,SPA 首选 |
| 2. 像素采样检测 | Canvas 取点判断颜色 | ⭐⭐⭐⭐⭐ | 中 | 对视觉要求高的场景 |
| 3. 性能 API 检测 | 监控 FCP/FP 时间 | ⭐⭐⭐ | 低 | 辅助判断加载慢 |
| 4. 错误监控 | 捕获 JS 报错 | ⭐⭐ | 低 | 定位原因,非直接检测 |
原理:在页面加载后(如 3 秒),检查应用根节点(如 #app)是否有子元素或特定内容。
function detectWhiteScreenByDOM() {
const rootElement = document.getElementById('app');
// 设定阈值时间,比如 3 秒后检查
setTimeout(() => {
if (!rootElement ||
rootElement.innerHTML.trim() === '' ||
rootElement.children.length === 0) {
reportWhiteScreen('DOM_EMPTY');
}
// 进阶:检查是否有特定关键元素(如导航栏、底部栏)
const criticalEl = document.querySelector('.main-content');
if (!criticalEl) {
reportWhiteScreen('CRITICAL_ELEMENT_MISSING');
}
}, 3000);
}
// 排除 Loading 状态(避免误报)
// 如果页面有 <div id="loading">,需先确认它已消失 ✅ 优点:实现简单,性能消耗极低,准确率高。
❌ 缺点:如果根节点里有"加载中..."文字,可能误判为有内容。
原理:利用 Canvas 截取屏幕关键点的像素,判断是否全为白色(或背景色)。
function detectWhiteScreenByPixel() {
setTimeout(() => {
const canvas = document.createElement('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext('2d');
// 通用替代方案:采样 9 个点
const points = [
{ x: 0.1, y: 0.1 }, { x: 0.5, y: 0.1 }, { x: 0.9, y: 0.1 },
{ x: 0.1, y: 0.5 }, { x: 0.5, y: 0.5 }, { x: 0.9, y: 0.5 },
{ x: 0.1, y: 0.9 }, { x: 0.5, y: 0.9 }, { x: 0.9, y: 0.9 }
];
let whiteCount = 0;
points.forEach(p => {
const x = Math.floor(window.innerWidth * p.x);
const y = Math.floor(window.innerHeight * p.y);
// 实际需配合 html2canvas 或后端截图服务
// if (isWhitePixel(x, y)) whiteCount++;
});
if (whiteCount >= 8) { // 9 个点 8 个是白色
reportWhiteScreen('PIXEL_ALL_WHITE');
}
}, 3000);
} 在真实项目中,建议采用以下分层检测策略:
使用 navigator.sendBeacon 发送数据,即使页面白屏卡死,数据也能发出。
function reportWhiteScreen(type) {
const data = JSON.stringify({
type,
url: location.href,
ua: navigator.userAgent,
time: Date.now()
});
// 优先 sendBeacon,不支持则 fallback 到 fetch
if (navigator.sendBeacon) {
navigator.sendBeacon('/api/monitor/white-screen', data);
} else {
fetch('/api/monitor/white-screen', {
method: 'POST',
body: data,
keepalive: true
});
}
} class WhiteScreenMonitor {
constructor(options = {}) {
this.delay = options.delay || 3000;
this.rootId = options.rootId || 'app';
}
init() {
// 1. DOM 检测
setTimeout(() => this.checkDOM(), this.delay);
// 2. FCP 检测
this.observeFCP();
// 3. 错误监听
this.listenErrors();
}
checkDOM() {
const root = document.getElementById(this.rootId);
if (!root || root.innerHTML.trim() === '') {
this.report('DOM_EMPTY');
}
}
observeFCP() {
let fcpTriggered = false;
new PerformanceObserver((list) => {
fcpTriggered = true;
const fcp = list.getEntries().pop();
if (fcp.startTime > 5000) this.report('FCP_SLOW');
}).observe({ entryTypes: ['paint'] });
setTimeout(() => {
if (!fcpTriggered) this.report('NO_FCP');
}, this.delay + 2000);
}
listenErrors() {
window.onerror = (msg) => this.report('JS_ERROR', { msg });
}
report(type, extra = {}) {
console.warn(`⚠️ 白屏预警:${type}`, extra);
// 调用 sendBeacon 上报
}
}
// 使用
new WhiteScreenMonitor().init(); "白屏检测我通常采用组合策略,因为单一方法有局限:
在之前的项目中,我还加了Loading 状态排除,避免用户正常等待时被误报。"