Page rendering is usually divided into front-end rendering and back-end rendering. Front-end rendering refers to the server returning the html framework and template, and the front-end pulls the data and renders the template through ajax asynchronous request, and dynamically modifys the dom to form the final page. Server-side rendering is when the server pulls data on the backend and renders the complete page and returns to the client. The two methods have their own benefits. Back-end rendering brings benefits such as increasing the first-screen time, reducing the number of requests, and benefiting SEO. However, traditional backend direct rendering requires waiting until the entire web page is rendered before returning to the client. If a block pulls data slowly, which affects the rendering speed, then for users, it will also become longer while waiting. Can back-end rendering be the same as front-end ajax rendering, and traditional server-side rendering in blocks and regions, a solution will be provided below - web page segment rendering.
First, let’s take a look at the traditional rendering method:
const http = require("http");const fs = require("fs");var tpl1 = '<!DOCTYPE html><html><head><title>test render</title></head><body>helloword<p>$data1</p>';var tpl2 = '<p>$data2</p></body></html>';var html = '';var server = http.createServer((req, res)=>{ if(req.url!=="/favicon.ico"){ res.writeHead(200, { 'Content-Type' : 'text/html' }); getDataOne((data1) => { getDataTwo((data2) => { res.end(tpl1.replace(//$data1/g, data1) + tpl2.replace(//$data2/g, data2)); }) }); } }); } }); } }).listen(3000, '127.0.0.1'); function getDataOne(fn){ setTimeout(() => { fn('111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 fn('222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222Above we provide a simple example to return a page by visiting http://127.0.0.1:3000. When rendering the page, there are 2 operations that take 5 seconds, which can be assumed to be IO or data pull. At this time, the time we observe the return page is 10 seconds, which means it takes 10 seconds for the user to see the page.
Next, we transform the backend rendering method and change it to segmented rendering.
const http = require("http");const fs = require("fs");var server = http.createServer((req, res)=>{ if(req.url!=="/favicon.ico"){ res.writeHead(200, { 'Content-Type' : 'text/html', 'Transfer-Encoding' : 'chunked' }); getDataOne((data1) => { res.write('<!DOCTYPE html><html><head><title>Test render</title></head><body>helloword<p>$data1</p>'.replace(//$data1/g, data1)); getDataTwo((data2) => { res.end('<p>$data2</p></body></html>'.replace(//$data2/g, data2)); }) }); }); }); }); }); }); }); }); }).listen(3000, '127.0.0.1'); function getDataOne(fn1){ setTimeout(() => { fn1('11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 fn2('22222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222By setting the http header: Transfer-Encoding: chunked, the magic of segmented transmission is enabled. This encoding method exists in http1.1. Generally, the information size cannot be determined when the server generates HTTP responses. At this time, the length cannot be written in advance with Content-Length, and the message length needs to be generated in real time. The server generally uses Chunked encoding.
When performing Chunked encoding transmission, there is transfer-coding at the head of the reply message and is defined as Chunked, indicating that the content will be transmitted using Chunked encoding. Let's take a look at the modified effect:
Although the overall page transfer time has not changed, in this way, we have reduced the response time by half, reducing the user's waiting time. In specific business, we can say that the parts that users need to see first are output in advance, and the backend process the long-term parts of the backend to output, which is the advantage of segmented transmission rendering. Note that if the server is nginx, it is possible that segmented rendering may be invalid due to buffer settings, and the buffer size needs to be adjusted.