背景小段子
- 刚拿到需求,初读业务代码
我:请求就请求吧,绕个弯子最后不还是一个样就是拿到数据?这不脱了裤子放屁嘛。
- 开发完了,带着上面的疑问
我:xx姐(我mentor),咱项目里请求那一块….,这样写啥用意啊?
xx姐:可能是…巴拉巴拉吧拉(不是xx姐写的,但她一听就懂了)
- 最后
我:真妙,我格局小了啊
plus:
虽然心里有其他迫不及待想搞的东西,但这个小玩意值得一记。
时刻记着皓哥的话——“搞前端一定要提升自己的业务能力,自己在业务中学到什么要时刻总结,永远不要学麻了。“
项目场景介绍
顶层路由结构:
可以看到顶层路由中有若干模块,其中学在当下模块的子路由结构:
本次需求就是开发学在当下模块下的每日精选
、专业课
、兴趣课
、课题组
四个子模块,概括来说,说白了就是每个模块分别对应发一个请求获取数据,然后展示即可。
请求逻辑
就不直接上源代码了,大致用关键代码概括一下项目里请求的相关操作(被我形容“脱了裤子放屁”的请求逻辑)。
1.组件内如何使用请求来的数据
专业课模块对应的组件ProfessionalCourses.vue
:
import {professional} from '@/store/learn';
export default defineComponent({
setup() {
...
// 从professional仓库中获取数据
const cardData = professional.getData();
const otherInfos = professional.getOtherInfos();
const subMenuList = professional.getBigClassList();
...
}
})
其他三个模块同理,每日精选
、兴趣课
、课题组
三个路由组件中分别在'@/store/learn'
中引入了一个对象,从中访问渲染所需的数据
2.请求来的数据存储在哪里
看一下professional
以及其他三个模块引入的对象的来源@/store/learn/index.ts
:
const daily = new DailyStore();
const subject = new SubjectStore();
const professional = new ProfessionalStore();
const interests = new InterestsStore();
const initDataFun = () => {
...
setTimeout(async () => {
await daily.refreshData();
await professional.refreshData();
await interests.refreshData();
await subject.getSubjectCount();
await subject.refreshData(1, 10);
await getBigClassList();
}, 0);
...
};
export {
daily,
subject,
professional,
interests,
...
initDataFun,
};
说白了对应每一个模块创建了一个对象,然后initDataFun
函数的核心逻辑就是调用每个对象的refreshData
等方法,说白了就是封装的发送请求的方法,然后把请求来的数据挂载到对象用来存储的属性上。
3.发送请求的时机
发送请求说白了就是调用initDataFun
函数,项目里选择在学在当下
(顶层路由组件)的beforeEnter
路由守卫中调用,router.ts
:
const routes: Array<RouteRecordRaw> = [
// 父级路由:学在当下模块
{
path: '/learn',
name: 'LearnView',
component: LearnView,
// 四个子路由模块
children: [
{
path: '',
name: 'LearnIndex',
redirect: '/learn/recommend'
},
{
path: 'recommend',
name: 'RecomendDailyCourses',
component: RecomendDailyCourses,
},
{
path: 'professional',
name: 'ProfessionalCourses',
component: ProfessionalCourses,
},
{
path: 'interests',
name: 'InterestsCourses',
component: InterestsCourses,
},
{
path: 'subject',
name: 'SubjectCourses',
component: SubjectCourses,
}
],
// 学在当下模块的beforeEnter路由守卫中调用initDataFun函数,来发送请求获取数据
beforeEnter(to, from, next) {
initDataFun();
...
},
},
}
总结
通过上面的核心代码我们就理清了整个数据流,说白了就是进入父级路由之前,我们调用initDataFun
函数,这个函数触发父路由组件的四个子路由的数据请求操作,然后子路由中直接导入存储了数据的对象,拿到数据使用即可。
思考🤔
针对如上的操作有什么利与弊以及可以学习的地方呢
- 利:进入学在当下模块时就请求了四个子模块渲染所需要的数据,这样相当于提前发送请求,切换子模块(路由组件)时就不用发送请求了,增加切换的流畅度
- 弊:增加初次进入学在当下模块时的网络请求压力,占用网络资源
启发:
说白了这一手操作相当于提前进行一些网络请求以备后续使用,这样在某些请求压力不大的时机在保障首屏体验的前提下完全可以用来优化后续体验。我就考虑极端情况下我们完全可以手动控制一些请求时机问题从而优化网络资源的使用率,进而优化项目性能。举个例子,与学在当下
同级的顶层路由页面首页
,本身作为功能的入口页面,加载压力很小,是不是完全可以在首页时就调用initDataFun
函数从而预先请求后续要使用的资源呢。(我试了,把initDataFun
放在首页
模块逻辑中执行,当转跳到学在当下
模块时明显的非常流畅😄)
当然如果我们把精力放在网络资源的分配上,自然会增加心智负担,肯定是不可行的,而且在不相关的代码处配置网络请求逻辑容易造成逻辑混乱,所以我觉着请求逻辑可以适当提前,但不要过度提前,最起码要在数据即将使用的时间节点再发送请求。
这种控制网络请求时机从而充分利用网络资源的行为不失为一种前端的“负载均衡”。
原文链接:https://juejin.cn/post/7218157956335976509 作者:荣达