前端循环依赖

前端中循环依赖

什么是循环依赖: 两个以上模块之间互相引用,构成闭环依赖。

保持依赖引入的单向流通性!

示例:

不要觉得自己不会写出这样的代码,当项目庞大后一旦出现这样的问题将会造成无法排查的问题。

复制代码
// 在a.js 引用 b.js 内容
import {b} from "./b.js"
export const a = () => {
  omit...
}
// 在b.js 引用 a.js 内容
import {a} from "./a.js"
export const b = () => {
  omit...
}

1、 为什么循环依赖会造成报错

循环依赖产生之后报错的原因,通常是由模块执行顺序造成的。

1.1 执行顺序

执行的顺序导致的模块先后加载时,出现未定义未初始化的报错。

ES6 modules

在ES6模块中,模块的加载顺序是由它们在代码中的出现顺序决定的。因此,如果两个模块相互引用,那么先出现的模块将先执行。

CommonJS

在CommonJS模块中,模块的加载顺序是由require函数的调用顺序决定的。因此,如果两个模块相互引用,那么先调用require函数的模块将先执行。

1.2 ES6 和 CommonJS 输出的值是和原始值是什么关系?(修改导出的值是否会影响原始值)

CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。 -- 《ECMAScript 6 入门教程》

CommonJS 模块确实输出的是一个值的拷贝。当你使用 module.exports 导出一个值时,这个值是被复制的,而不是被引用的。这意味着,如果你导出一个对象,那么对这个对象的修改不会影响到其他模块。

ES6模块使用 export 关键字来导出值,并且默认情况下,这些值是被引用的,而不是被复制的。这意味着,如果你导出一个对象,那么对这个对象的修改会影响到其他模块。但是,有一种情况下,ES6模块会创建一个值的拷贝,那就是当你使用 export 导出一个函数或者类的时候。在这种情况下,函数或者类的代码会被复制,但是任何在函数或者类中引用的外部变量仍然会被引用。

2、实际案例

假设现在你有一个 redux/store.ts 文件 和 api/http.ts 文件,分别为store仓库和axios请求。你需要在http文件中触发redux,来触发token的设置和清除,这是再正常不过的一个操作了吧。

http.ts 文件引入store,并视图通过store实例身上的方法修改state(通常是token)

import axios from "axios";

import store from "@/redux/store";

...omit

目前的依赖关系 http.ts => store.ts

实际的请求文件login.ts,引入http.ts 暴露的axios

import http from "@/api";

...omit

目前的依赖关系 login.ts => http.ts

store 下某个切片文件 authSlice.ts 引用了login.ts里的请求

import { getAuthButtonListApi, getAuthMenuListApi } from "@/api/modules/login";

目前的依赖关系 authSlice.ts => login.ts

由于authSlice 会被并入store

import { combineReducers } from "@reduxjs/toolkit";

import authReducer from "./authSlice";

export default combineReducers({

auth: authReducer,

});

目前的依赖关系 , store.ts => authSlice.ts

最终的依赖关系变为 store.ts => authSlice.ts => login.ts => http.ts => store.ts,最终居然形成了循环依赖!

3、项目如何避免循环引用

本质上如何避免循环引用,就是用监测手段 循环引用 并及时切断。

3.1 集成在webpack等脚手架的循环依赖分析

webpack插件名字 circular-dependency-plugin

3.2 集成在EsLint的循环依赖分析

EsLint插件名字 eslint-plugin-import ,eslint 规则 import/no-cycle

3.3 dpdm 开源插件

插件名字 dpdm 使用 dpdm 定位 JavaScript/TypeScript 中的循环依赖

3.4 TS项目类型

使用 import type {} from './xxx' 模块的类型定义,而不导入实际的模块内容。而不加type则会类型和实际值都被导入

相关推荐
ALONE阿龙太原微码1 小时前
微信小程序包体积优化:2MB 到 400KB 的实操记录
前端
掘金挖土1 小时前
前端手摸手跑路之 AI 应用开发(十一)
前端·后端
创了么OPC1 小时前
小程序能收款了,对公户还没开?独立开发者的交付闭环踩坑②
前端·微信小程序
IT_陈寒1 小时前
Vue动态组件缓存的坑你踩过了吗?
前端·人工智能·后端
寂寞狼牙冷1 小时前
封装fetch替换axios
前端
用户461169657281 小时前
网站 HTTPS 不稳定?证书排查指南
前端
n87652 小时前
Playwright Java WEB UI 自动化实现框架与逻辑
java·前端·ui
keyipatience2 小时前
TypeScript学习(1)
前端·javascript·学习·typescript·html·css3
xifangge20252 小时前
基于 JavaScript 实现 CNC 数控切削参数与螺纹公差纯前端核算引擎
开发语言·前端·javascript
wangruofeng3 小时前
2026 Web 技术选型指南,AI 时代如何选择适合项目的技术栈
前端·aigc·ai编程