思考!worker_threads 是否可以让 React 服务端渲染飞一把?
发布于 6 年前 作者 Lizhooh 6279 次浏览 来自 问答

最近 Nodejs 又有新的动作了,这次又是什么呢?在 Nodejs v10.5.0 里,提供了一个全新的实验性 API:worker_threads,也就是原生的 Nodejs 多线程支持,它似乎是为解决某些问题而出现。👏👏👏

该 worker_threads 模块提供了一种创建在独立线程上运行的多个环境并在它们之间创建消息通道的方法。 worker_threads 对执行 CPU 密集型 JavaScript 操作非常有用,但是不要将它们用于 I/O 处理,因为 Nodejs 异步执行操作的内置机制已经比 worker_threads 更有效地对待它。 与子进程或使用 cluster 模块不同,工作人员可以通过传输 ArrayBuffer 实例或共享 SharedArrayBuffer 实例来有效地共享内存。

我们知道,在 React 服务端渲染里 renderToString 是一个同步并且具有复杂计算的函数(纯计算函数)。在请求并发量大的时候,大部分的 CPU 都花费在 renderToString 里用于在服务端渲染初始标记以及计算校验和时间,这很可能会阻塞 Nodejs 的事件循环,并影响其他传入服务器的请求处理。

现在有了 worker_threads 后,我们尝试可以把 renderToString 放在一个子线程里执行,从而降低对主线程的影响。🐠🌂

// myRenderToString.js
const {
    Worker,
    isMainThread,
    parentPort,
    workerData
} = require('worker_threads');

if (isMainThread) {
    // 主线程
    module.exports = async function myRenderToString(component) {
        return new Promise((resolve, reject) => {
            const worker = new Worker(__filename, {
                workerData: component            // <-- 待渲染的组件。
            });
            worker.on('message', resolve);       // <-- 收到小弟的结果。
            worker.on('error', reject);
            worker.on('exit', (code) => {
                if (code !== 0) {
                    reject(new Error(`Worker stopped with exit code ${code}`));
                }
            });
        });
    };
} else {
    // 子线程
    const { renderToString } = require('react-dom/server');
    // 在子线程里渲染,这样就不会因为 renderToString 影响主线程处理网络请求。
    const HTML = renderToString(workerData);
    // --> 向老大,发送结果。
    parentPort.postMessage(HTML);
}

// index.js
const myRenderToString = require('./myRenderToString');
const App = require('./Client/app');

router.get('/', async ctx => {
    const html = await myRenderToString(<App initState={state} />);
    ctx.body = renderHTML({
        title: 'React 服务端渲染',
        body: html,
        state: JSON.stringify(state),
    });
});

目前,worker_threads 才刚出,很多 API 还不齐全和稳定,到底能不能让 React 服务端渲染飞一把? 拭目以待哈。😊😊😊

timg.gif

6 回复

用napajs, webworker-threads,这些模块 它们可内建线程,比进程通信更高效

来自酷炫的 CNodeMD

期待,目前已经用上了react的后端渲染,感觉速度已经快的飞起了(www.boxopened.com,你们感受下),等这个稳定成熟了,再来试试。

在想着以后可能出现这样的框架。

主进程初始化,然后每一个请求就开一个worker去动态执行。执行完之后销毁worker.

这样常驻内存的只有master,并且业务代码热更新,参考PHP。

一种猜测

From Noder

@GGBond1989 很强势…体验很好

是好事儿,不过是增强而已,不必太在意。

回到顶部