我注意到reactDOM.renderToString()
在服务器上渲染大型组件树时,该方法开始显着减慢。
背景
一点背景。该系统是一个完全同构的堆栈。最高级别的App
组件呈现模板、页面、dom 元素和更多组件。查看 react 代码,我发现它渲染了大约 1500 个组件(这包括任何被视为简单组件的简单 dom 标签,<p>this is a react component</p>
.
在开发中,渲染约 1500 个组件需要约 200-300 毫秒。通过删除一些组件,我能够在约 175-225 毫秒内获得约 1200 个组件来渲染。
在生产中,大约 1500 个组件上的 renderToString 大约需要 50-200 毫秒。
时间似乎是线性的。没有一个组件是缓慢的,而是许多组件的总和。
问题
这会在服务器上产生一些问题。冗长的方法导致服务器响应时间长。TTFB 远高于应有的水平。对于 api 调用和业务逻辑,响应应该是 250 毫秒,但是对于 250 毫秒的 renderToString,它会加倍!对 SEO 和用户不利。此外,作为一种同步方法,renderToString()
可以阻止节点服务器并备份后续请求(这可以通过使用 2 个独立的节点服务器来解决:1 个作为 Web 服务器,1 个作为单独渲染反应的服务)。
尝试
理想情况下,在生产环境中 renderToString 需要 5-50 毫秒。我一直在研究一些想法,但我不确定最好的方法是什么。
思路一:缓存组件
任何标记为“静态”的组件都可以被缓存。通过将缓存与渲染标记保持一致,renderToString()
可以在渲染之前检查缓存。如果它找到一个组件,它会自动抓取字符串。在高级组件上执行此操作将保存所有嵌套子组件的安装。您必须将缓存的组件标记的反应 rootID 替换为当前的 rootID。
想法 2:将组件标记为简单/愚蠢
通过将组件定义为“简单”,react 应该能够在渲染时跳过所有生命周期方法。React 已经为核心的 react dom 组件( , 等)做到了这<p/>
一点<h1/>
。扩展自定义组件以使用相同的优化会很好。
想法 3:在服务器端渲染上跳过组件
不需要服务器返回的组件(没有 SEO 值)可以简单地在服务器上跳过。客户端加载后,设置一个clientLoaded
标志true
并将其传递下来以强制重新渲染。
关闭和其他尝试
到目前为止,我实现的唯一解决方案是减少在服务器上呈现的组件数量。
我们正在关注的一些项目包括:
- React-dom-stream (仍在为测试实现这个)
- Babel 内联元素 (似乎这与想法 2 一致)
有没有人遇到过类似的问题?你能做什么?谢谢。