之前一个同学问我搞过bigpipe没有,当时也不知道这个是什么东东,网上找了一些资料之后自己实现了一个。
bigpipe的大体思路是分解网页成叫做Pagelets的小块,然后通过Web服务器和浏览器建立管道并管理他们在不同阶段的运行。
具体的概念和优缺点就不在这里复制粘贴了,网上一大把,有兴趣的可以在:
http://www.searchtb.com/2011/04/an-introduction-to-bigpipe.html 看一看
bigpipe的页面结构很简单,它分成主页面和子页面(pagelet)2个部分。
服务器向浏览器发送响应时候,先把主页面的内容flush出来。然后服务器开启数个线程对各个子页面进行处理,完成之后一个一个flush到主页面的底部。
先看一下主页面代码例子:
<body>
<div id="p1"></div>
<div id="p2"></div>
<div id="p3"></div>
sdfsfasfdafsdf
</body>
例子很简单,p1、p2、p3就是用来定义3个pagelet的位置的。当子页面被flush到页面尾部后,通过一个json字符串定义子页面的内容、样式、和javascript代码。
json格式如下:
{
pid:string, //pid定义了这个pagelet需要放置的页面位置,对应主页面的p1、p2、p3
css:string, //定义该pagelet需要用到的css文件
js:Array, //定义pagelet用到的数个js文件
html:string //pagelet的html内容
}
根据这个json的格式后台给页面输出的内容大概是这样样子的:
<script>bigpipe.create({"css":"/bigpipe/css/page2.css","html":"\r\n\r\n\r\n2:null <br>\r\n\r\n2:null <br>\r\n\r\n2:null <br>\r\n\r\n2:null <br>\r\n\r\n2:null <br>\r\n\r\n2:null <br>\r\n\r\n2:null <br>\r\n\r\n2:null <br>\r\n\r\n2:null <br>\r\n\r\n2:null <br>\r\n\r\n2:null <br>\r\n\r\n2:null <br>\r\n\r\n2:null <br>\r\n\r\n2:null <br>\r\n\r\n2:null <br>\r\n\r\n2:null <br>\r\n\r\n2:null <br>\r\n\r\n2:null <br>\r\n\r\n2:null <br>\r\n\r\n2:null <br>\r\n\r\n","js":["/bigpipe/js/page2.js"],"path":"/pagelet2.jsp","pid":"p2"});</script>
每一个pagelet被flush之后会立即调用bigpipe.create:
var bigpipe = (function () {
var headObj = document.getElementsByTagName("head")[0];
var bodyObj = document.getElementsByTagName("body")[0];
function loadCss(obj,fn) {
var link = document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
link.href = obj.css;
headObj.appendChild(link);
Event.bind(link,"load",function(){
fn(obj);
});
}
function loadJs(jsSrc) {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = jsSrc;
bodyObj.appendChild(script);
}
return {
create:function (obj) {
if (!obj.pid) {
return;
}
var fn=function(obj){ //注意一下这里,html和js不是立即写入页面中,而是作为回调函数等css加载完毕后再写入。
Log.d(obj);
document.getElementById(obj.pid).innerHTML=obj.html; //指定位置填写html代码
for(var i=0,len=obj.js.length;i<len;i++){
loadJs(obj.js[i]); //加载js文件
}
}
loadCss(obj,fn); //加载css
}
};
})();
pagelet组件加载的顺序是:css-->html-->js。由于css是异步加载的,如果先写入html再加载css可能会影响用户体现,为了保证让css加载完毕后才显示网页内容,注意一下loadcss方法,这里是等到css加载完毕后才写入html和加载js。
代码如附件(注:这里用到了公司的一个写日志的jar包,压缩包里是没有的,如果想编译通过把openEAP的依赖去掉然后把所有写日志的部分注释掉就行)