Bigpipe是产生于Facebook公司的前端加载技术,它的提出主要是为了解决重数据页面的加载速度问题。(《深入浅出nodejs》)
场景
假设有如下页面:页面主体是文章列表,页面底部为版权所有信息,两者数据均来自服务器端,其中获取文章列表数据比较慢,而获取版权信息数据则相对较快。以往的服务器模型是必须等到两者数据都得到后,再一起返回,然而获取更快的数据其实可以提前返回给客户端进行展示。这就需要使用Bigpipe技术了
这里有个疑问,为什么不用ajax?
网上说Bigpipe相比ajax有3个好处:
AJAX 的核心是XMLHttpRequest,客户端需要异步的向服务器端发送请求,然后将传送过来的内容动态添加到网页上。如此实现存在一些缺陷,即发送往返请求需要耗费时间,而BigPipe 技术使浏览器并不需要发送XMLHttpRequest 请求,这样就节省时间损耗。
使用AJAX时,浏览器和服务器的工作顺序执行。服务器必须等待浏览器的请求,这样就会造成服务器的空闲。浏览器工作时,服务器在等待,而服务器工作时,浏览器在等待,这也是一种性能的浪费。使用BigPipe,浏览器和服务器可以并行同时工作,服务器不需要等待浏览器的请求,而是一直处于加载页面内容的工作阶段,这就会使效率得到更大的提高。
减少浏览器发送到请求。对一个5亿用户的网站来说,减少了使用AJAX额外带来的请求,会减少服务器的负载,同样会带来很大的性能提升。
实现
前端
html1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Bagpipe示例</title>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/underscore.js/1.8.3/underscore-min.js"></script>
<script src="/static/bigpipe.js"></script>
</head>
<body>
<h2>下面是文章列表:</h2>
<div id="body"></div>
<script type="text/template" id="tpl_body">
<div><%=articles%></div>
</script>
<h2>下面是版权所有:</h2>
<div id="footer"></div>
<script type="text/template" id="tpl_footer">
<div><%=copyright%></div>
</script>
</body>
</html>
<script>
var bigpipe = new Bigpipe()
bigpipe.ready("articles", function (data) {
$("#body").html(_.template($("#tpl_body").html())({articles: data}))
})
bigpipe.ready("copyright", function (data) {
$("#footer").html(_.template($("#tpl_footer").html())({copyright: data}))
})
</script>
bigpipe.js
这里的bigpipe其实类似于一个发布/订阅模式:
1 | var Bigpipe = function () { |
后端
后端首先是实现了一个简单的路由解析系统:
1 | var fs = require('fs') |
然后,匹配路由/articles
,其中回调函数中首先返回html页面,并模拟两个不同时长的任务,任务完成后向客户端返回不同的js代码,用于触发客户端中对应任务的执行,等到两个任务均完成时终止输出:
1 | app.get('/articles', function (req, res) { |
在浏览器中打开localhost:1337/articles
,2秒后copyright部分显示出来,然后浏览器一直处于加载中的状态,约8秒后文章列表部分显示出来。