好处

React16推出了流式服务端渲染,它允许你并行地分发HTML片段。这样可以让渲染

出的首字节有意义的内容给用户速度更快。



(例子1,上面部分是一次性转换,下面是流渲染,两种方式)

而且相对renderToString,流是异步的。这个可以让你的Node.js服务一次性渲染多个请求,并且保持在高请求压力环境下的及时响应。在一个持续的时间内,如果网络阻塞了,它可以停止React的渲染,并且不会因为重的网络请求影响其他轻请求。

实现: 用renderToNodeStream

import { renderToNodeStream } from 'react-dom/server';
import Frontend from '../client'; app.use('*', (request, response) => {
// 一开始发送有意义的页面部分
response.write('<html><head><title>Page</title></head><body><div id="root">');
// 把组件渲染成流,并且给Response
const stream = renderToNodeStream(<Frontend />);
stream.pipe(response, { end: 'false' });
// 当React渲染结束后,发送剩余的HTML部分给浏览器
stream.on('end', () => {
response.end('</div></body></html>');
});
});

(以上是例子2)

流是怎么工作的

renderToNodeStream返回了一个可读流,可以比作水龙头:它有源源不断的水,只是被堵住了,等待别人把它拧开。如果用这个可读流(如果把水龙头打开),只需要监听“data”时间就可以了(如果有新数据到了会自动触发)

代码类似这样:

import { renderToNodeStream } from 'react-dom/server';
const stream = renderToNodeStream(<Frontend />);
stream.on('data', (data) => {
console.log(JSON.stringify(data));
});

但是我们看例子2并没有监听”data“事件,而是直接把流pipe给了response对象。其实啊,

response对象在Node.js中是一个可写流,可以比做下水道。可读流通过pipe给可写流时,

可读流的数据会被分块发给可写流(就像是水龙头直接和下水道连接了一样,水源源不断流通)。

可写流可以对数据(水)进行任意的处理。

在我们的例子中,我们把组件渲染出来的流(html片段)给了response,response会把片段发给请求的客户端(比如浏览器)。



(可以看到First Byte明显前移动了,说明流渲染更快;因为并行的原因,片段渲染也更快了)

在Node.js中缓存HTML

const originalSend = response.send;
response.send = (html, ...other) => {
// 保证不缓存错误状态
if (response.statusCode > 100 && response.statusCode < 300) cache.put(request.path, html)
originalSend(html, ...other);
}

采用Express的中间件,提供缓存文件服务:

app.use('*', (request, response, next) => {
if (cache.has(request.path)) {
//如果缓存中有这个路径,则返回HTML
cache.get(request.path).then(html => response.send(html));
} else {
//否则就直接渲染
next();
}
})

接下来的问题是:如何渲染HTML,当你直接把htm的可写流pipe给了response流。因为response.send不会再被调用了,你也无法访问整个HTML文档。

缓存流HTML:transform streams

transform streams是什么?它就像是一个水龙头的过滤器。可读流经过它转换后才会给可写流。

在我们这里,我们只是想要缓存HTML并不会转化数据,具体怎么做,看代码:

import { Transform } from 'stream';

const createCacheStream = (key) => {
const bufferedChunks = [];
return new Transform({
//每一个HTML片段都会调用 transform()
transform(data, enc, cb) {
// 把HTML片段(Buffer)保存在内存中
bufferedChunks.push(data);
// 数据原封不动地给到下一个可读流
cb(null, data);
}, // 当所有的事件都做完后会调用flush()
flush(cb) {
// 通过连接HTML片段得到完整的html
// 并缓存起来
cache.set(key, Buffer.concat(bufferedChunks))
cb();
}
});
}

然后我们可以在我们的服务端渲染代码中使用它:

app.use('*', (request, response) => {
// 通过过滤器(transform streams)创建了缓存
let cacheStream = createCacheStream(request.path);
// cachesStream接上Response
cacheStream.pipe(response);
//先把首部分写到cacheStream
cacheStream.write('<html><head><title>Page</title></head><body><div id="root">');
// 创建了渲染流
const renderStream = renderToNodeStream(<Frontend />);
// 渲染流接上cacheStream
renderStream.pipe(cacheStream, { end: false });
renderStream.on('end', () => {
// 一旦结束渲染则做剩余部分的输出
cacheStream.end('</div></body></html>');
});
})

以上就是主要内容

原文链接:

https://zeit.co/blog/streaming-server-rendering-at-spectrum?nsukey=uW6M5M2uTd6F3Nc1u6tAVuAMGhbsBnpEuVplgUQLBlKevYZGGYN%2Bi1m6RocmDu%2F9367Zl71zSNn%2BkcWnaXcdX7bmeFLEyjbMMVsl5VtaBTfAvX8iNXgXMdbYWxVuuAealdKz8wkNfwEQtp4yLxknnredPgKISZUp%2BuR420YfPbpg8dW1lJMnpBMwNAJYMFZ0

作者知乎/公众号:前端疯 (一群热爱前端的一线程序员维护,想要用前端改变世界。)

(译文)React----React应用程序流式服务端渲染的更多相关文章

  1. 教你如何在React及Redux项目中进行服务端渲染

    服务端渲染(SSR: Server Side Rendering)在React项目中有着广泛的应用场景 基于React虚拟DOM的特性,在浏览器端和服务端我们可以实现同构(可以使用同一份代码来实现多端 ...

  2. react+redux教程(六)redux服务端渲染流程

    今天,我们要讲解的是react+redux服务端渲染.个人认为,react击败angular的真正“杀手锏”就是服务端渲染.我们为什么要实现服务端渲染,主要是为了SEO. 例子 例子仍然是官方的计数器 ...

  3. React 在服务端渲染的实现

    原文地址:Server-Side React Rendering 原文作者:Roger Jin 译者:牧云云 React 在服务端渲染的实现 React是最受欢迎的客户端 JavaScript 框架, ...

  4. [译]React 在服务端渲染的实现

    原文地址:Server-Side React Rendering 原文作者:Roger Jin React 在服务端渲染的实现 React是最受欢迎的客户端 JavaScript 框架,但你知道吗(可 ...

  5. React 服务端渲染最佳解决方案

    最近在开发一个服务端渲染工具,通过一篇小文大致介绍下服务端渲染,和服务端渲染的方式方法.在此文后面有两中服务端渲染方式的构思,根据你对服务端渲染的利弊权衡,你会选择哪一种服务端渲染方式呢? 什么是服务 ...

  6. React 16 服务端渲染的新特性

    React 16 服务端渲染的新特性 React 16 中关于服务端渲染的新特性 快速介绍React 16 服务端渲染的新特性,包括数组.性能.流等 React 16 终于来了!

  7. react基础学习和react服务端渲染框架next.js踩坑

    说明 React作为Facebook 内部开发 Instagram 的项目中,是一个用来构建用户界面的优秀 JS 库,于 2013 年 5 月开源.作为前端的三大框架之一,React的应用可以说是非常 ...

  8. react+laravel与服务端渲染的几点思考

    一.前后端完全分离 1.用React.js做MVC中的V,剩下的交给Laravel 2.Laravel用来做API接口开发. 3.好处:实现了前后端开发的分离,从而加快前后端开发效率.另外若是多端的如 ...

  9. React 服务端渲染方案完美的解决方案

    最近在开发一个服务端渲染工具,通过一篇小文大致介绍下服务端渲染,和服务端渲染的方式方法.在此文后面有两中服务端渲染方式的构思,根据你对服务端渲染的利弊权衡,你会选择哪一种服务端渲染方式呢? 什么是服务 ...

随机推荐

  1. nest exception is java.sql.SQLException:ORA-01476:除数为0

    1.错误描述 nest exception is java.sql.SQLException:ORA-01476:除数为0 2.错误原因 3.解决办法

  2. C#扩展方法类库StringExtensions

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  3. FPGA 状态机设计

    数字系统有两大类有限状态机(Finite State Machine,FSM):Moore状态机和Mealy状态机. Moore状态机 其最大特点是输出只由当前状态确定,与输入无关.Moore状态机的 ...

  4. Scrapyd日志输出优化

    现在维护着一个新浪微博爬虫,爬取量已经5亿+,使用了Scrapyd部署分布式. Scrapyd运行时会输出日志到本地,导致日志文件会越来越大,这个其实就是Scrapy控制台的输出.但是这个日志其实有用 ...

  5. 易理解java代码8皇后问题

    马上就要蓝桥杯比赛了,我这些算法还是不会,确实有点慌,今天一天早上睡到很晚不愿起床,然后才开始研究8皇后问题.这也是典型的回溯与递归问题.其实本质上和马踏棋盘问题非常类似,八皇后问题呢,就是要判断主对 ...

  6. springtest-junit-jidi--测试接口

    一,问题分析 假如在一个项目中要测试一个接口,但是这个项目没有对外开放url地址,话句话就是说浏览器访问不了里面的资源,自己造的数据不能测试接口,那么只能等别人来调用自己的接口,而且自己也不能测试,假 ...

  7. jquery初始化的三种方式

    第一种 $(document).ready(function(){ alert("第一种方法."); }); 第二种 $(function(){ alert("第二种方法 ...

  8. 【BZOJ2555】SubString(后缀自动机,Link-Cut Tree)

    [BZOJ2555]SubString(后缀自动机,Link-Cut Tree) 题面 BZOJ 题解 这题看起来不难 每次要求的就是\(right/endpos\)集合的大小 所以搞一个\(LCT\ ...

  9. THUWC2018滚粗记

    THUWC2018滚粗记 前言 又是一篇滚粗记, 不过可能还要写过很多很多篇滚粗记, 才会有一篇不是滚粗记的东西啦 总而言之,我现在还是太菜了 还要过一大段时间我才会变强啦 Day -inf 联赛考完 ...

  10. 异步解决方案promise及源码实现

    js语言的特性,造就了特别的异步处理方式,我记得以前用的最多的就是回调函数,那个时候写jquery的ajax时候,特别喜欢写这种代码: $.ajax({ method:'get', url:" ...