共计 1647 个字符,预计需要花费 5 分钟才能阅读完成。
说起数据加载的机制,有一个绕不开的话题就是前端性能,很多电商门户的首页其实都会做一些垂直的定制优化,比方让申请在页面最早加载,或者在前一个页面就进行预加载等等。随着 react18 的公布,申请机制这一块也是被一直谈起,并且在后续其实也给出了明确的方向。
如果咱们页面中有三个组件 C1、C2、C3 顺次嵌套,每个组件中有对应的申请 F1、F2、F3,通常大多数人会应用 useeffect 和 state 变量来实现数据流的获取,这样就意味着必须在组件加载时能力发动申请,所有数据获取都产生在组件的生命周期中,如下图所示,咱们能够将这种获取数据的形式称作瀑布流渲染,然而这种形式有一个问题是,在这种办法中,组件之间的数据获取是按程序进行的,这实际上意味着它们彼此阻塞,如果组件的层级嵌套很深的话,就会导致页面的加载工夫特地长。
为了阻止组件间数据获取的这种程序阻塞,另一种办法就是在组件加载前能够应用 Promise.all 获取所有的申请数据,这样在组件加载时就曾经获取到所有的数据了。这种形式解决了组件加载程序阻塞彼此数据流获取的问题,然而也产生了一个新的问题,在申请实现之前页面都会是空白的。
基于第二种先申请后渲染的形式,还能够应用 Suspense 将申请和渲染并行化,Suspense 能够使得组件能够“期待”某些操作完结后,再进行渲染。而这种形式如果要用到理论我的项目中,还须要思考 C1、C2、C3 对应的申请写在哪里,如果写在组件中,那么加载还是慢的。如果拆分进去,就须要思考文件拆分、code splitting 等工程化问题。
在认真的剖析了以上三种形式当前,发现各有优劣,同时基于上述计划,我也提供一个申请优化的思路,首先将申请的 JS 独自拆分进去打一个文件 request.js,在 html 头部引入 request.js 并应用 async 属性让脚本并行执行(如下代码所示),这样既能够保障咱们的申请在最开始就能收回,也能不阻塞后续 React 代码打包的 js 文件的执行,相当申请和渲染的代码在并行执行。
// html 头部引入 request.js
<script async src="/js/request.js"></script>
在发送完申请之后,须要将返回的数据注入到 React 组件中,这部分怎么注入呢?简略的代码示例如下:
// request.js 中申请局部 evt 是公布订阅模式的一个实例
window.InitData = {
data: null,
on: (msg, fn) => evt.on(msg, e => fn(e)),
emit: (msg, data) => evt.emit(msg, data),
};
fetch().then(rs => {
InitData.data = rs;
InitData.emit("init_data", rs);
return rs;
});
// index.js react 代码逻辑
…….
useEffect(() => {if (InitData.data !== null) {
// 这里曾经获取到了申请的返回值
doSomething();} else {InitData.on("init_data", (data) => {
// 利用公布订阅模式获取到数据
doSomething();});
}
}, []);
…….
总体思路就是在 html 中最先加载独自打包进去的申请文件并退出 async 属性使脚本并行执行,将返回的数据挂载到 window 下或者利用公布订阅模式将数据注入到 react 组件中。这样其实相似于边申请边渲染的模式,利用提前申请来缩小加载的工夫。后续也是心愿能用工程化的形式去解决数据的申请机制。
将来的话在开发时必定是更偏向于边申请边渲染的这种模式,在 React 的官网中也有说到将来打算让 Suspense 解决更
多的场景,包含获取数据等等,在新公布的 React18 中 Suspense 也是反对了服务端渲染,包含近期开源的 remix 也都在优化申请机制可能让利用更快的加载。也欢送有趣味的小伙伴一起来探讨和实际。
作者:京东批发 梁峰峰
起源:京东云开发者社区