前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >介绍bigpipe以及bigpipe在django上的实现

介绍bigpipe以及bigpipe在django上的实现

作者头像
Bob.Chen
发布2018-05-02 14:01:11
1.2K0
发布2018-05-02 14:01:11
举报

什么是BigPipe

关于BigPipe是在看一篇淘宝ued的官方博客上看到的,原文是说用nodejs做前后端分离的,只是稍微提了一下bigpipe。 感兴趣的同学也可以看一下那篇文章,http://ued.taobao.org/blog/2014/04/full-stack-development-with-nodejs/

于是百度之,发现bigpipe是由facebook最先提出,个人感觉是个非常有意思的想法。 关于bigpipe的介绍,网上有很多,这里简单说一下:

我们平常打开网页通常都是串行的,服务器收到请求后,开始各种渲染页面,等页面全部渲染好之后,再返回给浏览器,而在渲染过程中,浏览器则一直处于等待状态。

加入服务器有几个耗时的操作,总共需要花费10秒,则在这10秒钟内,浏览器属于一片空白,用户体验很不好。而bigpipe则是服务器接受到请求之后,立马返回一段骨架html,但是不包括闭合的body和html标签,这时候response并没有结束,每当服务器端准备好一块数据,就立即flush给浏览器,浏览器在收到骨架html之后,就立即开始渲染,之后每得到一段数据都进行渲染。

这样的好处是,也许整个页面也需要10秒才能完全显示出来,但是浏览器在第一秒就开始有东西显示。

还有一点需要特别说明的是,bigpipe使用javascript渲染页面,也就是说返回的是一对script标签,里面是一段javascript代码,这样的好处是,渲染页面的时候不会被块位置束缚,并且服务器支持多线程处理的话,可以同时处理多块内容,哪块先处理好,就flush回浏览器,不用在意html代码的物理顺序。后面每段返回的pagelet

也许有人会有疑问,咋看起来,BigPipe和Ajax非常像,那他们有什么不同呢。 主要的不同点在于,Ajax每一块需要单独发送一个HTTP请求,建立连接的开销是比较大的,而BigPipe只有一个HTTP请求。所以Ajax相对于BigPipe来说,对服务器造成的压力更大。

开干

网上关于BigPipe的实现有很多,php和node.js是用的比较多的。

下面说下在python django框架下,实现一个BigPipe的例子,也方便大家理解BigPipe的思想。

首先,我们创建一个骨架模板,这个就是服务器在接收请求后,立即返回的html:

代码语言:javascript
复制
<!DOCTYPE html>  
<html>  
<head>  
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>  
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>  
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <script type="text/javascript" src="/site_media/js/prototype.js"></script>  
    <script type="text/javascript" src="/site_media/js/prototypepatch.js"></script>  
    <script type="text/javascript" src="/site_media/js/bigpipe.js"></script>

    <title>{{title}}</title>  
</head>  
<body >  
    <div id="content_0"></div>  
    <div id="content_1"></div>  
    <div id="content_2"></div>  
    <div id="content_3"></div>  
    <div id="content_4"></div>  
    <div id="content_5"></div>  
    <div id="content_6"></div>  
    <div id="content_7"></div>  
    <div id="content_8"></div>  
    <div id="content_9"></div> 
</body>
</html>

这段代码主要是有10个div,待会儿我们返回的内容就放在这些div里面,注意这里没有 和 这里引入了三个js文件,我们后面再说。

然后就是接收请求的django view:

代码语言:javascript
复制
import time  
from django.http import StreamingHttpResponse  
from django.template.loader import render_to_string

def test(request):  
    return StreamingHttpResponse(stream_response_generator())

由于我们不立即返回整个请求,所以并不直接返回HttpResponse对象,而是返回StreamingHttpResponse对象,并且这里的stream_response_generator函数返回的是生成器。 关于python里面的生成器,请百度关键字yield。

stream_response_generator方法如下:

代码语言:javascript
复制
def stream_response_generator():

    yield render_to_string('bigpipe.html', {"title":"BigPipe Test Page"})  
    for x in range(0,10):  
        is_last = False  
        if x == 9: is_last = True  
        pagelet = dict(id="content_%s" % x, get_html_content=x,   
                        get_css_resources="", get_js_resources="",   
                        is_last=is_last )  
        yield render_to_string('pagelet.html',{'pagelet':pagelet})

        time.sleep(1)  
    yield "</body></html>\n"

yield render_to_string('bigpipe.html', {"title":"BigPipe Test Page"})这句就是把骨架html返回。

之后每次都会返回一段pagelet,代码为:yield render_to_string('pagelet.html',{'pagelet':pagelet})。

之后休息1秒再返回下一段pagelet,这个是为了模拟服务器耗时操作。

最后返回和标签: yield "</body></html>\n"

这里用了一个叫pagelet.html的模板文件,如下:

代码语言:javascript
复制
<script type="text/javascript">  
  BigPipe.onArrive({  
    id: '{{ pagelet.id }}',   
    innerHTML: '{% filter escapejs %}{{ pagelet.get_html_content }}{% endfilter %}',   
    css_files: ["/site_media/css/head.css", "/site_media/css/home.css"],   
    js_files: ["/site_media/js/utils.js"],   
    is_last: {{ pagelet.is_last|yesno:"true,false" }}  
    });  
</script>

这段javascript里面用到的BigPipe对象就是我们一开始在骨架HTML中引入的bigpipe. js中提供的,bigpipe.js依赖于prototype库。 bigpipe.js的github地址为:https://github.com/msroot/bigpipe 这里简单说下几个参数的意思:

  • id: 这个就是要把html放到哪个id下面,比如我们要放到id为content_0的div下面,这里就填content_0;
  • innerHTML: 就是具体的html代码;
  • css_files: 这段html代码依赖的css,bigpipe.js会先加载css文件,并且相同的css文件只会加载一次;
  • js_files: 这段html代码依赖的js文件,bigpipe.js会最后加载js文件,基本是等所有pagelet加载完才开始加载js文件;
  • is_last: 标识这个pagelet是否是最后一个。

下图是用firebug看到的整个请求过程:

网页上的0到9,基本是一个一个出来的,间隔约1秒,整个请求是10.04秒,其中等待响应时间只有26毫秒。 还要注意一点就是响应头中的 Transfer-Encoding:chunked也就是告诉浏览器,这个是分段返回的。

还有一点,apache等http服务器会对返回进行一定的缓存,也就是等有一定数量的文本再返回,这样我们如果直接跑上面的代码,不会得到我们预期的结果,这里需要把apache的mod_deflate模块给disable掉,在配置文件中加上: SetEnvIf Request_URI ^/mysite no-gzip=1 关于更多disable mod_deflate模块的信息,可以参考http://stackoverflow.com/questions/1922934/how-to-disable-mod-deflate-in-apache2

至此,大概就可以了解了bigpipe的整个思想,以及在django上的实现。

总结一下

  • BigPipe是个非常有意思的想法,并且已经在Facebook以及淘宝等大型公司使用了比较长时间。很可能是未来前端优化,提升用户体验的主要手段。
  • 还有一点不足,由于要依赖于客户端javascript进行一部分html渲染的工作,所以服务器端返回的pagelet中的js代码要依赖于浏览器中javascript的实现,有些库用innerHTML表示需要填充的html,有些库用content等(一开始就吃了这个亏,还好可以看bigpipe.js的源代码)。所以貌似没有一个统一的标准,这样不方便写通用的库。
  • 对于SEO来说,需要实现当蜘蛛来的时候在服务器组装好全部页面,然后返回。

延伸阅读

一些介绍BigPipe的文章: http://www.searchtb.com/2011/04/an-introduction-to-bigpipe.html http://huoding.com/2011/06/26/88

javascript的bigpipe: https://github.com/msroot/bigpipe

一个django关于bigpipe的扩展,但是4年前就没更新了,可以看看源码,领会精神: https://github.com/orygens/django-bigpipe https://pypi.python.org/pypi/django-bigpipe

django关于bigpip的一些内容: http://www.slideshare.net/gagedark/even-faster-django-27352247 (需要访问外国网站) http://www.slideshare.net/slawdan/bigpipe1126adev (也需要访问外国网站)

django返回stream content: http://stackoverflow.com/questions/2922874/how-to-stream-an-httpresponse-with-django

Node.js的bigpipe实现: https://bigpipe.io/ https://github.com/bigpipe/bigpipe.js

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2015-02-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是BigPipe
  • 开干
  • 总结一下
  • 延伸阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档