zoukankan      html  css  js  c++  java
  • (译文)React----React应用程序流式服务端渲染

    好处

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

  • 相关阅读:
    layUI table.reload 刷新表格
    js实现 StringBuilder
    sqlServer 重复数据项处理,只选其中一条,保留一条
    在唯一密钥属性“name”设置为“XXX”时,无法添加类型为“add”的重复集合项
    sqlserver 把 某一列的所有值 变成 in 里面的内容
    初识第三方登录
    卸载vsto插件的方法
    layui-框架学习小总结
    c# 记一次批量获取自己的qq好友的CF游戏战绩
    得到qq正在登录的qq的号
  • 原文地址:https://www.cnblogs.com/xunxing/p/39481f7f8b0afea05b78fff25529f005.html
Copyright © 2011-2022 走看看