使用Nashorn Engine进行React Server-Side Rendering

简介: 几个月前上线了一个电子商务系统平台,运用React开发前web前端,Groovy开发后端 REST API,应用性能及前端交互的响应非常好,但是有一个非常大的痛点。 整个React应用包括库与应用代码在minfy之后仍然超过`2MB`。

几个月前上线了一个电子商务系统平台,运用React开发前web前端,Groovy开发后端 REST API,应用性能及前端交互的响应非常好,但是有一个非常大的痛点。

整个React应用包括库与应用代码在minfy之后仍然超过2MB。当用户第一次访问应用浏览器无缓存时,页面一片空白,原因是浏览器需要下载JavaScript文件。即使已经使用webpack进行代码分割,访问页面仍需要下载1.5MB以上Javascript。在一个250KB/s的下载带宽下,页面可能需要~8秒才能首次渲染。这严重影响用户体验。

解决单页应用的首次渲染方案很明显是进行Server-Side渲染。在google了一些解决方案后,大多数文章及demo都是基于NodeJS,这也很自然,前后端都是JavaScript技术栈。因为web端采用了React,手机端采用了React Native,所以使用NodeJS也行。不过因为后端技术栈主要是Groovy运行于JVM上,所以采用NodeJS会增加部署的复杂度,尤其是当每个用户企业需要部署一个应用实例的话,每个用户企业都要部署一个NodeJS与JVM,从扩展角度来看不够经济。

JDK 1.7开始增加了Nashorn Script Engine,可以在JVM上运行JavaScript。网上关于运用Nshorn进行Server-Side Rendering的文章很少。有一篇非常好,Project Nashorn – JavaScript on the JVM,详细解释了Nashorn Script Engine的特性。

React包括Angular 2VueJS,都不直接操作DOM,而是操作所谓Virtual DOM(一种实际DOM的中间表示),通过定期的reconciliation比较上次渲染的差异后批量进行DOM操作。 在Server端渲染时可直接生成html,因此不需要DOM的环境。

由下图可见

bb87feef79cc56d1e69f5bc24e2c3838

引自 https://blog.codecentric.de/files/2014/06/specifications.png

Nashorn仅实现了ECMAScript,如同Chrome的JavaScript内核一样。因此如果在Nashorn上进行React应用渲染,我们需要自己提供XMLHttpRequest specHTML 5 Spec(section 6)的polyfill。在JavaScript中经常使用的Promise, Fetch等可以通过JavaScript进行polyfill,如很多人使用的core-js

Github上有段代码关于polyfill Nashorn。我下载下来,运行正常。但过了段时间后遇到一个问题,偶尔会有一些请求在服务器端挂起直到timeout。如果通过apache bench进行并发测试在100请求40并发下大约有7%的请求挂起直到timeout。这肯定无法进行生产运用。

几天前突然在Youtube上看到一段视频。Philip Roberts详细了Event Loop如何工作的。于是我基于之前的代码增加了nashornEventLoopDeque),Timer Task运行时往nashornEventLoop尾部增加一个function callback的对象。Nshorne Engine线程调用nashornEventLoop.process()从队列头部取function callback的对象进行函数回调。结果很惊人,挂起问题解决,即使大并发测试也无问题。

经过仔细理解与验证,原来在之前版本的polyfill中使用了Timer Task运行function callback,实际上它是运行于另外一个线程(不同于Nashorn Engine的线程),可能会同时操作一个JavaScript对象从而损坏Nashorn Engine线程的Javascript调用栈。在后面版本Timer的线程只是往nashornEventLoop队列上增加function callback对象,从而不会损坏Nashorn Engine线程JavaScript调用栈,同时通过Phaser协调Nashorn Engine线程与Timer线程同一时间只有一个能访问nashornEventLoop队列。

性能测试显示,在Macbook Pro (2.3G 4核,16G内存,SSD), 能够实现~40请求/秒,JVM内存占用600MB~1.1GB,服务器上理应更高

81d6b3168c44f482f49f7e5efc3e1ff1

现在Server-Side Rendering解决方案除了NodeJSJVM Nashorn Engine也是可靠的一种。

相关github库:

目录
相关文章
|
1月前
|
前端开发 JavaScript 测试技术
React Server Side Rendering (SSR) 详解
【10月更文挑战第19天】React Server Side Rendering (SSR) 是一种在服务器端渲染 React 应用的技术,通过在服务器上预先生成 HTML 内容,提高首屏加载速度和 SEO。本文从概念入手,逐步探讨 SSR 的实现步骤、常见问题及解决方案,并通过代码示例进行说明。
229 3
|
4月前
|
开发者
🔥揭秘JSF导航:如何轻松驾驭页面跳转与流程控制?🎯
【8月更文挑战第31天】在 JavaServer Faces(JSF)中,导航规则是控制页面跳转和流程的关键。本文详细介绍 JSF 的导航规则,包括转发和重定向等跳转方式,并通过 `faces-config.xml` 文件配置示例展示如何实现不同场景下的页面跳转及流程控制,帮助开发者有效管理应用程序的页面流和用户交互,提升应用质量。
61 0
|
4月前
|
前端开发 搜索推荐 UED
React Server Side Rendering的神奇之处:如何用SSR提升SEO与首屏加载速度,让你的项目一鸣惊人?
【8月更文挑战第31天】在现代Web开发中,React服务器端渲染(SSR)能显著提升SEO性能和首屏加载速度。通过在服务器端预渲染组件并发送HTML至客户端,SSR不仅优化了首屏加载时间,增强了用户体验,还生成了便于搜索引擎抓取的静态HTML文件,提升了页面排名。此外,SSR还具备提高安全性的优点,能够有效防范XSS攻击。虽然其开发复杂性和服务器负载是潜在劣势,但借助如Next.js等库、编写高效组件及定期维护等最佳实践,可以充分发挥SSR的优势,为未来Web开发注入更强动力。
69 0
|
7月前
|
设计模式 前端开发 数据可视化
【第4期】一文了解React UI 组件库
【第4期】一文了解React UI 组件库
387 0
|
7月前
|
存储 前端开发 JavaScript
【第34期】一文学会React组件传值
【第34期】一文学会React组件传值
80 0
|
7月前
|
前端开发
【第31期】一文学会用React Hooks组件编写组件
【第31期】一文学会用React Hooks组件编写组件
83 0
|
7月前
|
存储 前端开发 JavaScript
【第29期】一文学会用React类组件编写组件
【第29期】一文学会用React类组件编写组件
83 0
|
7月前
|
前端开发 开发者
【第26期】一文读懂React组件编写方式
【第26期】一文读懂React组件编写方式
70 0
|
7月前
|
资源调度 前端开发 JavaScript
React 的antd-mobile 组件库,嵌套路由
React 的antd-mobile 组件库,嵌套路由
132 0
|
7月前
|
存储 前端开发 中间件
React组件间的通信
React组件间的通信
59 1