name | title | tags | categories | info | time | desc | keywords | |||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
几小点说明为何KeepAlive组件不是最终解决方案 |
几小点说明为何KeepAlive组件不是最终解决方案 |
|
瞎折腾 |
清明时节雨纷纷,组件缓存欲断魂 |
2024/4/4 |
几小点说明为何KeepAlive组件不是最终解决方案 |
|
大多数框架都提供了基于组件维度 KeepAlive 的缓存机制,然而,前端使用<keep-alive></keep-alive>
组件来进行性能优化永远只能是暂时的,最简单的道理就是,UI 的渲染成本已经越来越低了,何况还有 VDOM,用 display:none 属性保存 DOM 结构完全是一种增加心智负担且没有必要的行为。大多数场景下,前端想要缓存的永远是组件中的数据。
但是如果是一个用合理的 Headless 架构构建出来的应用程序,它的状态原本就是独立在外层,一层层业务层像洋葱一样把 UI 组件包裹住的,只要页面不关闭,外层的业务层所代表的组件根本不会销毁,所以根本不需要 keep-alive 组件。一旦 UI 重新挂载需要重新加载数据,完全可以让业务层下发这个刷新的能力,让 UI 组件在挂载的生命周期触发即可(或者遵循 MVC 架构,把业务 UI 组件再分成纯 View 组件和 Control 组件,在 Control 组件的生命周期去做这件事情)。
这个结论同样也能支持反例,假如使用 keepAlive 组件来包裹 A 组件和 B 组件,那么只要业务够复杂,就一定会遇到 A 组件中的一个小组件 Aa 和 B 组件中的一个小组件 Ba 同属于同一个业务的情况。此时如果业务需要 A 组件和 B 组件不被缓存,但是每次渲染的时候 Aa 和 Ba 又不能重新渲染,在不使用 Store 的情况下,KeepAlive 组件只能通过一些很丑陋的 Include 和 Exclude 来穿透监听,完全违背了职责分离原则。
而如果使用 Store,那么其实还是抛弃了 KeepAlive 的组件缓存机制,走了上面所说的数据与 UI 对应的机制,因为很明显 UI 在这里是经过了两次不同的渲染的。甚至我们说在如今前端框架普遍提供了类似于 inject 和 provide 的时代,Store 的存在也显得没有必要了。因为不同业务之间的 Store 相互引用,很容易让不同的业务之间形成网状的结构,其结果就是状态刷新时牵一发而动全身,难以摸清规律。所以如今我们会更倾向于使用简单的 Provide 和 Inject 来让数据之间形成嵌套式的关系,如果遇到共同的依赖,那就再抽离一层子层同时依赖双方,进行双边逻辑的处理,让整个数据流始终保持在自外向内的洋葱结构中,以便在数据刷新时,能够最小化的刷新对应的业务层。
结论:前端不应该局限于基于组件级别使用 KeepAlive 进行缓存,前端缓存的最终目标一定是基于业务层的状态进行分层缓存。