说起数据加载的机制,有一个绕不开的话题就是前端性能,很多电商门户的首页其实都会做一些垂直的定制优化,比方让申请在页面最早加载,或者在前一个页面就进行预加载等等。随着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也都在优化申请机制可能让利用更快的加载。也欢送有趣味的小伙伴一起来探讨和实际。

作者:京东批发 梁峰峰

起源:京东云开发者社区