前端循环依赖

前端中循环依赖

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

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

示例:

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

复制代码
// 在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则会类型和实际值都被导入

相关推荐
TeleostNaCl2 小时前
解决 Chrome 无法访问网页但无痕模式下可以访问该网页 的问题
前端·网络·chrome·windows·经验分享
前端大卫3 小时前
为什么 React 中的 key 不能用索引?
前端
你的人类朋友3 小时前
【Node】手动归还主线程控制权:解决 Node.js 阻塞的一个思路
前端·后端·node.js
小李小李不讲道理5 小时前
「Ant Design 组件库探索」五:Tabs组件
前端·react.js·ant design
毕设十刻5 小时前
基于Vue的学分预警系统98k51(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js
mapbar_front6 小时前
在职场生存中如何做个不好惹的人
前端
牧杉-惊蛰6 小时前
纯flex布局来写瀑布流
前端·javascript·css
一袋米扛几楼987 小时前
【软件安全】什么是XSS(Cross-Site Scripting,跨站脚本)?
前端·安全·xss
向上的车轮7 小时前
Actix Web适合什么类型的Web应用?可以部署 Java 或 .NET 的应用程序?
java·前端·rust·.net
XiaoYu20027 小时前
第1章 核心竞争力和职业规划
前端·面试·程序员