使用Nashorn Engine進行React Server-Side Rendering

幾個月前上線了一個電子商務系統平臺,運用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的環境。

由下圖可見

nashorn specifications

引自 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,服務器上理應更高

ab-snapshot

現在Server-Side Rendering解決方案除了NodeJSJVM Nashorn Engine也是可靠的一種。

相關github庫:

魔石招聘應用採用了JVM Nashorn進行React Server-Side Render。瞭解更多見Demo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章