重构缓存时踩的坑:注释了三行没用的代码却导致白屏

大家好,我是奈德丽。我又又又来分享我的经验了。

背景

最近项目的缓存越来越混乱,各种store、localStorage、sessionStorage到处都是,维护起来简直是噩梦。于是我决定花点时间重构一下缓存逻辑,让代码更清爽一些。

事故现场

在清理代码的过程中,我打开了 文件,发现里面有一些看起来没用到的store相关代码。

我就注释了没被用到的三行代码

1. 顶部的import语句:

javascript 复制代码
/* 我注释的第一行代码
 import { useVerifyStore } from '@/stores/index.js'
 */

2. beforeEnter钩子中的代码: if语句底下是原本就注释的代码,所以我看到整个文件没有对useVerifyStore去使用,心想着先给他注释了吧,结果就白屏了

javascript 复制代码
{
  path: '/ticketBook',
  name: 'ticketBook',
  component: () => import('../pages/ticketBook/index.vue'),
  beforeEnter: (to, from, next) => { 
     /*这是我注释的第二行和第三行代码
     let useVerifyStoreObj = useVerifyStore() //验价store
     let { query } = to
    */
    next();
    //这是原本就注释了的代码
    // if (!useVerifyStoreObj.verifyObj.verifyRefTraceId) {//没有验价
    //    next({
    //     path: '/preloadLoading',
    //     query,
    //   });
    // } else {
    //   next();
    // }
  }
}

心想:"这些代码看起来没啥用啊,验证功能我也没在这个路由里看到相关逻辑,而且都被注释了",于是就很自然地把它们彻底删除了,也就注释了三行代码。

保存,刷新页面...

白屏!

整个应用直接挂了,控制台报错如下:

从错误信息可以看到:

  • Uncaught ReferenceError: Cannot access 'useBaggageUtils' before initialization
  • 还有一些关于事件监听器的警告

这说明模块初始化顺序出了问题,i18n在还没初始化完成时就被访问了。

排查过程

第一反应:懵逼

我当时的心情就是:???

明明只是注释了一些看起来无关紧要的代码,怎么整个应用都崩了?难道这些代码有什么魔法?

深入调查

既然问题出在这些代码上,我就开始追踪这个依赖链条:

1. router/index.js 的依赖关系

javascript 复制代码
import {createRouter,createWebHistory,createWebHashHistory} from 'vue-router'
import { Base64 } from "js-base64";
import qs from 'qs'
import CurrencyAll from '@/pages/components/Currency/currency.js'
import { useVerifyStore } from '@/stores/index.js'  // 这里引入了stores
import { getEncryptionStr,getDecryptionStr } from '@/utils/index.js'
import { eventTracking } from '../server/request';
import { FlightSearchParams } from '@/utils/paramsModels.js'
import {setLangFromBrowser} from '@/utils/switchLanguage.js'  // 这里也引入了switchLanguage
import ExpiredLinkPage from '@/pages/components/ExpiredLinkPage.vue';

2. stores/index.js 的依赖关系

javascript 复制代码
import { ref, computed, reactive, toRefs } from 'vue'
import { defineStore } from 'pinia'
import { handleOfferData } from '@/utils'
import axios from '@/server/axios.js'
import apis from '@/server/api'
import { Languages } from "@/utils/enums";
import { useI18n } from 'vue-i18n'
import * as vant from 'vant'
import Decimal from 'decimal.js'
import { createEsimLogic } from '@/utils/esimUtils.js'
import vantLanguage from '@/utils/vantLanguage'
import { flushLanguageCallbacks } from '@/utils/switchLanguage'  // 又引入了switchLanguage!
import { useBaggageAndOtherPoliclesStores } from './baggageAndOtherPoliclesStores'

3. utils/switchLanguage.js 的依赖关系

javascript 复制代码
import { useGlobalStore, useLocalGlobalStore } from '@/stores/index.js'  // 又引回了stores!
import apis from '@/server/api.js'
import axios from '@/server/axios.js'
import { generateUUID } from '.'

4. lang/i18n.js 的依赖关系

javascript 复制代码
import { createI18n } from "vue-i18n";
import {setLangFromBrowser} from '@/utils/switchLanguage.js'  // 也引入了switchLanguage
// ... 其他语言包导入

// 在初始化过程中调用
let langStore = localStorage.getItem('language');
if (langStore) {
  local = langStore
}else{
  const browserLang = navigator.language
  const langFromBrowser = setLangFromBrowser(browserLang)  // 这里调用了switchLanguage的函数
  if(langFromBrowser){
    local = langFromBrowser
  }
}

真相大白

卧槽!多重循环依赖!

依赖链条是这样的:

  1. router/index.jsstores/index.js
  2. stores/index.jsutils/switchLanguage.js
  3. utils/switchLanguage.jsstores/index.js (循环!)
  4. 同时,lang/i18n.jsutils/switchLanguage.js

原来是这样的:

  • 平时虽然存在循环依赖,但因为 router/index.jsuseVerifyStore() 的调用,让模块初始化有了一个稳定的顺序
  • 当我注释掉 import { useVerifyStore } from '@/stores/index.js'let useVerifyStoreObj = useVerifyStore() 后,模块加载顺序发生了变化
  • 某些工具函数(如useBaggageUtils)在还没初始化完成时就被访问了
  • 整个依赖链条崩塌,导致白屏

这就像是一个精妙的平衡系统,我以为自己只是拿掉了一个看似无用的零件,结果整个系统都垮了。

解决方案

实际解决方案:重构依赖结构

我的解决方法是把循环依赖的根源给切断了:

1. 创建独立的语言工具文件

setLangFromBrowser 方法从 switchLanguage.js 中分离出来,创建一个新的 languageUtils.js 文件:

javascript:e:\yuetu\voyawiser-mobile\src\utils\languageUtils.js 复制代码
// 纯函数,不依赖任何store
export function setLangFromBrowser(browserLang){
  // 浏览器语言映射逻辑
  const langMapping = {
    'zh-CN': 'zh_CN',
    'zh-TW': 'zh_TW',
    'zh-HK': 'zh_TW',
    'en-US': 'en',
    'en-GB': 'en',
    'ko-KR': 'ko',
    'es-ES': 'es',
    'fr-FR': 'fr',
    'de-DE': 'de',
    'it-IT': 'it',
    'nb-NO': 'nb_NO',
    'my-MY': 'my',
    'th-TH': 'th'
  }
  
  return langMapping[browserLang] || langMapping[browserLang.split('-')[0]] || null
}

2. 修改i18n.js的引用路径

javascript:e:\yuetu\voyawiser-mobile\src\lang\i18n.js 复制代码
// 原来的引用(会造成循环依赖)
// import {setLangFromBrowser} from '@/utils/switchLanguage.js'

// 新的引用(从独立文件引入)
import {setLangFromBrowser} from '@/utils/languageUtils.js'

3. 打破循环依赖链

这样就彻底切断了 i18n.jsswitchLanguage.jsstores/index.js 这条依赖链。

为什么这个方案有效

  • 根本性解决:不是绕过问题,而是从根源上解决了循环依赖
  • 最小改动:只需要创建一个新文件,修改一个引用路径
  • 清晰的职责分离:语言相关的纯函数独立出来,职责更清晰
  • 消除隐式依赖:不再依赖某个特定的模块加载顺序来维持稳定

教训总结

1. 看似无用的代码可能有隐藏作用

在重构时,不要轻易删除或注释看起来"无用"的代码,特别是在复杂的依赖关系中。有时候一行看似无关的代码可能在维持整个系统的平衡。

2. 循环依赖是定时炸弹

虽然JavaScript允许循环依赖,但这种设计本身就是有问题的。它让代码变得脆弱,一个小改动就可能引发连锁反应。

3. 重构要小步快跑

重构时应该:

  • 一次只改一个地方
  • 每次改动后都要测试
  • 使用版本控制,随时可以回滚
  • 理解代码的依赖关系再动手

4. 职责分离很重要

把纯函数和有副作用的函数分开,把工具函数和业务逻辑分开,这样可以大大减少不必要的依赖关系。

后续优化

这次事故让我意识到,项目的架构设计确实需要优化。后续计划:

  1. 继续梳理其他可能的循环依赖:使用工具分析整个项目的依赖图
  2. 建立更清晰的分层架构:utils层不应该依赖stores层
  3. 制定模块引用规范:避免循环依赖的编码规范
  4. 把更多的纯函数独立出来:减少不必要的依赖关系

结语

重构是好事,但要谨慎。特别是在复杂的项目中,看似简单的改动可能会触发意想不到的问题。

这次的经历告诉我:解决问题要从根源入手,不要只是绕过问题。

有时候,最简单直接的解决方案往往是最有效的!理解代码的依赖关系,比盲目地删除"无用"代码更重要。

大家觉得不错可以点点赞,收藏收藏。

emm,懦夫的味道...
相关推荐
xianxin_11 分钟前
CSS Dimension(尺寸)
前端
小宋搬砖第一名11 分钟前
前端包体积优化实战-从 352KB 到 7.45KB 的极致瘦身
前端
陈随易12 分钟前
前端之虎陈随易:2025年8月上旬总结分享
前端·后端·程序员
草巾冒小子16 分钟前
天地图应用篇:增加全屏、图层选择功能
前端
universe_0135 分钟前
day25|学习前端js
前端·笔记
Zuckjet40 分钟前
V8 引擎的性能魔法:JSON 序列化的 2 倍速度提升之路
前端·chrome·v8
MrSkye40 分钟前
🔥React 新手必看!useRef 竟然不能触发 onChange?原来是这个原因!
前端·react.js·面试
wayman_he_何大民1 小时前
初识机器学习算法 - AUM时间序列分析
前端·人工智能
juejin_cn1 小时前
前端使用模糊搜索fuse.js和拼音搜索pinyin-match提升搜索体验
前端
....4921 小时前
Vue3 + Element Plus 实现可搜索、可折叠、可拖拽的部门树组件
前端·javascript·vue.js