欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 创投人物 > 页面白屏出现的原因

页面白屏出现的原因

2025/3/13 15:51:27 来源:https://blog.csdn.net/weixin_45511682/article/details/146152650  浏览:    关键词:页面白屏出现的原因

在这里插入图片描述

🤖 作者简介:水煮白菜王,一位前端劝退师 👻
👀 文章专栏: 前端专栏 ,记录一下平时在博客写作中,总结出的一些开发技巧和知识归纳总结✍。
感谢支持💕💕💕

目录

  • 资源加载问题
    • 1.可恢复的白屏
    • 2.不可恢复的白屏
  • 代码执行错误
  • 白屏检测
    • 检测根节点是否渲染
    • Mutation Observer 监听 DOM 变化
    • 页面截图
  • 解决办法

白屏通常指的是页面打开后,浏览器上面的地址栏已经显示完整的 URL,但是页面内容无法渲染,只有白色的空白页面。
导致白屏的原因大致可分为两类:

  • 资源加载问题
  • 代码执行错误

从现代前端视角来看,这两种原因都跟当前SPA框架的广泛使用有关。

资源加载问题

这里的资源特指 JavaScript 脚本、样式表、图片等静态资源,不包括接口调用等动态资源。

资源加载问题导致的白屏可以分为可恢复的和不可恢复的两大类

1.可恢复的白屏

可恢复的白屏常见于第一次进人页面时,由于资源加载过慢或者接口请求未返回,所以浏览器无法执行下一步骤。
这种白屏通常是网络状况太差或者设备性能太差等原因导致的,一般在浏览器返回后,就能恢复页面渲染,可以通过监控首屏时间来发现。

如果生产环境的首屏时间呈异常上升趋势,那么一定是页面白屏时间过长导致的,开发人员应该及时关注并排查近期改动的代码

2.不可恢复的白屏

不可恢复的白屏大多是由于网络或缓存问题导致的。
常见的例子莫过于 React、Vue 等 SPA 框架构建的 Web 应用,一旦 [bundle|app].js 因为网络原因访问失败,便会引发页面白屏。

你可以访问任意SPA框架构建的Web应用,按照如下步骤复现:打开 DevTools > Network,找到 app.xxx.js,右键并选中 Block request URL,随后刷新页面。

另一个例子是SPA项目打包后,在非首次线上替换dist文件时,某些手机/浏览器在之后首次打开页面,可能出现白屏情况

在用户端会默认缓存index.html入口文件,而由于vue打包生成的css/js都是哈希值,跟上次的文件名都不同,因此会出现找不到css/js的情况,导致白屏的产生。在服务端更新包之后,由于旧的文件被删除,而index.html所链接的路径依然是旧文件路径,因此会找不到文件,从而白屏。

代码执行错误

代码执行错误导致的白屏一般伴随着功能流程的阻断出现,并且很难通过等待或者页面刷新等方法修复。
这类问题出现的原因通常是前端代码逻辑错误,或是后端接口的脏数据导致的前端数据解析逻辑错误,最终导致运行异常的前端代码触发了页面崩溃。

例如,如果 React 中的组件发生了异常,并且外部没有使用 componentDidCatch 或者getDerivedStateFromError 捕错误,那么 React 组件 render 挂载的目标节点下的 DOM 树会被移除、页面就会出现白屏。

自React 16 起,任何未被错误边界捕获的错误将会导致整个 React 组件树被卸载。

白屏检测

检测根节点是否渲染

这种方法的原理是在当前主流 SPA 框架下,DOM 一般挂载在一个根节点之下(比如 < div id=“app” > ),发生白屏后通常是根节点下所有 DOM 被卸载。
我们可以通过在页面渲染完成后,检查页面根节点的子元素是否存在,如果不存在,则可以判断页面是白屏状态。
这种方案简洁明了,但缺点也很明显,项目有骨架屏渲染的情况下无法判断是否白屏。
如在 Vue.js 中可以使用钩子函数 mounted 或 created 在页面渲染完成后进行检测。

export default {created() {// 获取页面根节点const rootNode = document.querySelector('#app');// 检测根节点的子元素是否存在if (rootNode.children.length === 0) {// 页面是白屏状态console.error('页面白屏了!');} else {// 页面正常显示console.log('页面正常显示');}},
}

由于 SPA 应用通常使用异步加载方式加载组件和数据,因此需要确保在页面组件渲染完成后再进行白屏检测。如果在组件渲染之前进行检测,可能会误判为白屏。另外,SPA 应用可能会存在某些异步请求失败或加载超时等问题,也需要考虑这些因素对白屏检测的影响。

Mutation Observer 监听 DOM 变化

Mutation Observer 是一种在 DOM 树发生变化时进行回调的方式,可以用于监听页面元素的变化。可以通过 Mutation Observer 来监听 DOM 树变化,从而判断页面是否白屏。
但这个方式的缺点也很明显:

  • 对性能的影响:使用 Mutation Observer 监听 DOM 变化会对浏览器性能造成一定影响,尤其是当 DOM
    树变化频繁时,会导致回调函数频繁执行,影响页面的响应速度和用户体验。
  • 兼容性问题:Mutation Observer 的兼容性不是很好,不同浏览器支持程度不同,需要进行兼容性处理。
  • 误判问题:有些情况下,页面并不是真正的白屏,但是 Mutation Observer 仍然会误判为白屏,例如页面中有一个空白的 div元素占位,此时即使页面内容未加载,也不会被判定为白屏状态。

具体实现步骤如下:

  1. 创建一个 Mutation Observer 实例,并指定回调函数。
const observer = new MutationObserver((mutations) => {// mutations 表示 DOM 树的变化列表
});
  1. 将 Mutation Observer 实例与根节点进行绑定,并指定监测的选项。
const rootNode = document.documentElement;
const observerConfig = {childList: true, // 监听子节点的变化subtree: true, // 监听所有后代节点的变化attributes: true, // 监听节点属性的变化characterData: true, // 监听节点文本内容的变化attributeOldValue: true, // 记录节点属性变化前的值characterDataOldValue: true, // 记录节点文本内容变化前的值
};
observer.observe(rootNode, observerConfig);
  1. 在回调函数中检查 DOM 树的变化,如果发现根节点的子元素存在,则可以判断页面不是白屏状态。
const observer = new MutationObserver((mutations) => {// 检查根节点的子元素是否存在if (rootNode.children.length > 0) {console.log('页面正常显示');} else {console.error('页面白屏了!');}
});

页面截图

通过对网页进行截图,对截图进行像素点分析,判断页面是否白屏。一般情况下,可以统计截图中所有像素点的 RGB 值,如果所有像素点的 RGB 值都相同,且与白色(RGB(255, 255, 255))非常接近,那么就可以判断页面是白屏状态。
这个方式的缺点如下:

  • 页面截图需要包含足够的像素点,以便能够准确地检测页面是否白屏。如果截图不够清晰,可能会导致误判。
  • 有些情况下,页面并不是真正的白屏,但是由于一些外部原因(例如网络问题)导致页面未加载,此时页面截图也会被判定为白屏状态。
  • 页面存在骨架屏的情况下,需要对比骨架屏

解决办法

思路:减小打包后的体积(sourceMap关掉,CDN引入, 路由懒加载,组件按需加载)

  • 提高渲染速度
  • 优化用户体验
  • CDN资源优化

将依赖的第三方npm包全部改为通过CDN链接获取,在index.html里插入相应链接

<body><div id="app"></div><script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script><script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.min.js"></script><script src="https://cdn.bootcss.com/vuex/3.1.0/vuex.min.js"></script><script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.min.js"></script><script src="https://cdn.bootcss.com/element-ui/2.6.1/index.js"></script>
</body>

在vue.config.js里配置externals属性

module.exports = {···externals: {'vue': 'Vue','vuex': 'Vuex','vue-router': 'VueRouter','axios':'axios','element-ui': 'ElementUI'}}

卸载相关依赖的npm包

npm uninstall xxx

使用gzip压缩

前端处理:

// npm i compression-webpack-plugin -S
const CompressionPlugin = require('compression-webpack-plugin');module.exports = {productionSourceMap: false,configureWebpack: config => {if (process.env.NODE_ENV === 'production') {return {plugins: [new CompressionPlugin({// 匹配规格test: /\.js$|\.html$|\.css$|\.png$/,// 文件超过多大进行压缩 单位Bytethreshold: 10240,// 是否删除源文件(建议不删除)deleteOriginalAssets: false})],}}},
}

还需要在 nginx开启gzip压缩, 例如:

 gzip on;gzip_static on; //当存在.gzip格式的js文件时,优先使用静态文件gzip_min_length  10k; //开启gzip压缩的最小大小gzip_buffers     4 16k;gzip_http_version 1.1;gzip_comp_level 6;gzip_types     text/plain application/javascript application/x-javascript text/javascript text/css application/xml;gzip_vary on;gzip_proxied   expired no-cache no-store private auth;gzip_disable   "MSIE [1-6]\.";

注意:

当nginx开启gzip压缩的时候,无论前端打包出来的文件是否压缩,网站加载到的js文件都是经过nginx实时压缩过的 。
当gzip_static off的时候,前端上传的js压缩文件(gzip格式那些)并没有什么用。
当gzip_static on时,优先加载前端打包的gzip压缩文件,如果没有找到该文件,那么nginx将实时压缩之后传给浏览器。

如果你觉得这篇文章对你有帮助,请点赞 👍、收藏 👏 并关注我!👀
在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词