问题复现(场景:小程序应用)
将VConsole下载到本地进行,在main.js中进行初始化,当上线后,页面首次加载会出现卡顿空白页,刷新之后显示正常
javascript
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import VConsole from 'vconsole'
new VConsole();
new Vue({
render: h => h(App),
router,
}).$mount('#app')
阻塞原因
首次加载无缓存 + VConsole 初始化抢占主线程,阻塞了页面渲染;第二次刷新有缓存,VConsole 加载 / 初始化耗时骤降,不再阻塞。
「第一次卡顿白屏」
当在 main.js 里直接 new VConsole() 时,会发生下面过程:
- ✅ 资源无缓存 :第一次进页面,浏览器要从网络下载
vconsole.js源码(约 150KB),占网络带宽,拖慢页面 JS 加载; - ✅ 抢占主线程:VConsole 初始化时,会做「重写 console、插 DOM 面板、监听网络请求」等操作,这些操作和 Vue 初始化、页面 DOM 渲染抢同一根「主线程」,浏览器顾此失彼,页面来不及渲染就白屏;
- ✅ 时序冲突 :VConsole 初始化和 Vue 挂载(
$mount('#app'))同时执行,甚至更早,直接打乱页面渲染节奏,导致首屏出不来。
2.「第二次就正常」
第二次进页面时:
- ✅ 资源有缓存 :浏览器已经把
vconsole.js存在本地,不用再从网络下载,加载耗时从几百毫秒降到几毫秒; - ✅ 初始化变快:VConsole 初始化的核心资源(如样式、面板模板)都在缓存里,主线程占用时间大幅减少,不会再阻塞 Vue 渲染和页面显示。
即使下载依赖到本地,只要在main.js立刻初始化同样会造成阻塞
加延迟让vue先完初始化,console再进行加载
加延迟解决卡顿
javascript
import { createApp } from 'vue'
import App from './App.vue'
// 1. 先挂载 Vue 应用
const app = createApp(App)
app.mount('#app')
// 2. 延迟初始化 VConsole(仅开发环境)
if (process.env.NODE_ENV === 'development') {
setTimeout(() => {
import('vconsole').then(({ default: VConsole }) => {
new VConsole()
})
}, 100)
}
虽然加延迟能解决卡顿,但是看不到初始化运行时加载的其他js文件
利用async和preload解决卡顿问题,但是会丢失少部分初始化最开始的加载日志文件
比如这样:、
xml
<head>
<!-- VConsole异步加载 -->
<script src="https://cdn.bootcdn.net/ajax/libs/vConsole/3.15.0/vconsole.min.js" async></script>
<!-- 项目JS正常引入(也可加async) -->
<script src="./js/chunk-vendors.js"></script>
<script src="./js/app.js"></script>
<script>
// 等页面所有资源加载完,再初始化VConsole(避免卡顿)
window.addEventListener('load', () => {
if (window.VConsole) { // 检查VConsole是否加载完成
new window.VConsole({ disableLogScrolling: true });
console.log('VConsole初始化完成(async方案)');
// 此时执行你的日志打印逻辑
window.printNewJS();
}
});
// 你的printNewJS等逻辑保留
window.printedJS = new Set();
window.printNewJS = function()
</script>
</head>
终极解决方案:先完成console的初始化再引入打包配的.js文件
xml
<head>
<!-- 预加载VConsole,加速下载 -->
<link rel="preload" href="https://cdn.bootcdn.net/ajax/libs/vConsole/3.15.0/vconsole.min.js" as="script">
<script>
// 先加载并初始化VConsole
const scriptVConsole = document.createElement('script');
scriptVConsole.src = "https://cdn.bootcdn.net/ajax/libs/vConsole/3.15.0/vconsole.min.js";
scriptVConsole.onload = () => {
new VConsole();
console.log('VConsole初始化完成');
// VConsole就绪后,动态引入项目JS(保留日志)
loadProjectJS();
};
document.head.appendChild(scriptVConsole);
// 动态引入项目JS(原逻辑)
function loadProjectJS() {
const projectJS = ['./js/chunk-vendors.js', './js/app.js'];
projectJS.forEach(path => {
const script = document.createElement('script');
script.src = path;
document.body.appendChild(script);
});
}
</script>
</head>
但是这样有一个缺点:会有一个短暂的空白,所以可以给idnex.html中加入一个loading提示过渡,这样就可以查看项目运行过程中整个所有加载的文件运行状态结果