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

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

作者头像
Bob.Chen
发布于 2018-05-02 06:01:11
发布于 2018-05-02 06:01:11
1.3K00
代码可运行
举报
运行总次数:0
代码可运行

什么是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
代码运行次数:0
运行
AI代码解释
复制
<!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
代码运行次数:0
运行
AI代码解释
复制
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
代码运行次数:0
运行
AI代码解释
复制
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
代码运行次数:0
运行
AI代码解释
复制
<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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
性能优化三部曲之三——Node直出让你的网页秒开
项目: 手Q群成员分布直出 原因: 为家校群业务直出做准备 群成员分布业务是小型业务,而且逻辑相当简单,方便做直出试验田 基本概念: 直出其实并不算是新概念。只不过在Web2.0单页应用流行的年代,一
李成熙heyli
2018/01/05
1.9K1
性能优化三部曲之三——Node直出让你的网页秒开
bigpipe性能优化
本文介绍了一种Web性能优化方案Bigpipe,通过将页面分解成多个小块,实现渐进式加载和渲染,提升了页面的加载速度。Bigpipe采用管道技术,将请求处理分为多个子过程,每个子过程可以并发处理一部分请求。通过合理设置延时和并发数,可以最大程度地减少请求处理时间,提高页面加载速度。同时,Bigpipe还采用了多种优化技术,如合并文件、直出HTML等,进一步提高了页面的加载速度。Bigpipe已经在Facebook等公司中得到应用,并取得了良好的效果。
IMWeb前端团队
2018/01/08
1.3K0
高性能流水线页面技术 BigPipe
网站速度是Facebook的重要目标,2009年,Facebook成功的使网站快了两倍,工程师团队为此做了多项创新,BigPipe就是其中的一个秘密武器 BigPipe重新设计了动态网页服务体系,大体
dys
2018/04/03
1.4K0
高性能流水线页面技术 BigPipe
前端-CSS与网络性能
在博客上,CSS 相关的文章却不多。那就结合 CSS 与性能这两大主题,为大家带来一篇文章吧。
grain先森
2019/03/29
9970
前端-CSS与网络性能
探索Django:从项目创建到图片上传的全方位指南
Django 是一个流行的 Python Web 开发框架,它提供了一系列工具和库,用于帮助开发人员构建高效、可扩展的 Web 应用程序。Django 的目标是让开发者能够以快速和简单的方式构建复杂的 Web 应用,通过提供许多预构建的组件和功能,如 ORM(对象关系映射)、表单处理、认证系统、管理界面等,从而降低了开发工作的复杂性。
努力的小雨
2024/05/11
3053
CSS和网络性能
CSS对于呈现页面至关重要 - 在找到,下载和解析所有CSS之前,浏览器不会开始呈现 - 因此我们必须尽可能快地将其加载到用户的设备上。 关键路径上的任何延迟都会影响我们的“开始渲染”并让用户看到空白屏幕。
frontoldman
2019/09/03
1.3K0
CSS和网络性能
04.Django基础四之模板系统
  当模版引擎遇到一个变量,它将计算这个变量,然后用结果替换掉它本身。 变量的命名包括任何字母数字以及下划线 ("_")的组合。 变量名称中不能有空格或标点符号。
changxin7
2019/09/29
2.6K0
让骨架屏更快渲染 - 知乎
在之前「为vue项目添加骨架屏」一文中,介绍了骨架屏的概念以及在 Vue 项目中的应用。本文将介绍如何加快浏览器对骨架屏的渲染。
ConardLi
2019/10/06
8650
Django个人博客,三小时带你入门Django框架
Django框架是时下Python语言最热门的Web框架之一,它是一个功能完善、文档齐全、开发敏捷、配置简单的Web框架,能够快速将一个想法实现,使用它能够快速搭建一个网站!
二爷
2020/07/22
6710
Django个人博客,三小时带你入门Django框架
django:自定义静态文件服务器
静态文件使用nginx是比较有效率的,但是有时,我们需要对文件下载做细粒度的处理,比如鉴权下载,此时就需要写代码了。 下面将一步步实现一个自定义的文件handler。
超级大猪
2019/11/21
1.4K0
【Javascript】BigPipe
传统请求周期: 浏览器发送一个HTTP请求到Web服务器; web服务器解析请求,然后读取数据存储层,制定一个HTML文件并用一个HTTP响应把它发送到客户端; HTTP响应通过互联网传送
前端修罗场
2023/10/07
1250
node.js实现BigPipe详解
BigPipe 是 Facebook 开发的优化网页加载速度的技术。网上几乎没有用 node.js 实现的文章,实际上,不止于 node.js,BigPipe 用其他语言的实现在网上都很少见。以至于这技术出现很久以后,我还以为就是整个网页的框架先发送完毕后,用另一个或几个 ajax 请求再请求页面内的模块。直到不久前,我才了解到原来 BigPipe 的核心概念就是只用一个 HTTP 请求,只是页面元素不按顺序发送而已。 了解了这个核心概念就好办了,得益于 node.js 的异步特性,很容易就可以用 node
春哥大魔王
2018/04/17
2K0
node.js实现BigPipe详解
Node.js实现的BigPipe
从加载到显示共消耗约13s (2 + 4 + 6 + 1 ~= 13s),符合预期结果
meteoric
2018/11/16
8350
白话BigPipe
所谓BigPipe,指的是Facebook开发的用来改善客户端响应速度的技术。本质上讲,其实它并不是新事物,原理上等同于Yahoo在Best Practices for Speeding Up Your Web Site里提出的Flush the Buffer Early,不过BigPipe的实现更灵活,所以有必要了解一二。
LA0WAN9
2021/12/14
4480
Django用户登录与注册系统
一、创建项目 1.1.创建项目和app django-admin startproject mysite_login python manage.py startapp login 1.2.设置时区和语言 Django默认使用美国时间和英语,在项目的settings文件中,如下所示: LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True 我们把它改为亚洲/上海时间和中文 LAN
zhang_derek
2018/04/11
11.4K0
Django用户登录与注册系统
使用Django构建即时通讯应用的最简单方法
模板中包括一个 EventSource 脚本,用于接收来自 Django 的服务器发送的事件。 在sim下创建templates文件夹,在templates下创建chat.html。写入:
一只大鸽子
2024/01/09
4090
使用Django构建即时通讯应用的最简单方法
Python Django个人网站搭建5-编写文章详情页面并支持markdown语法
作者: zifanwang  发布于2020-05-09
zifan
2021/12/14
4660
Python Django个人网站搭建5-编写文章详情页面并支持markdown语法
Django之文件上传下载
在文件上传期间,实际文件数据存储在request.FILES中。此字典中的每个条目都是UploadedFile对象(或子类) – 上传文件的简单包装器。UploadedFile对象是对Python file对象的一个简单封装,并带有Django特定的附加功能。需要表示文件的时候,Django内部会使用这个类。UploadedFile对象拥有下列属性和方法:
菲宇
2022/05/06
3.4K0
django之文件上传下载等相关
实现步骤: 1)创建项目Django_upload:django-admin startproject Django_upload;创建app:cd Django_upload;python manage.py startapp blog。 2)设计模型(M) 这里的模型只包括了两个属性:用户名(即谁上传了该文件);文件名。具体形式如下所示: #coding=utf-8 from __future__ import unicode_literals from django.db import models class NormalUser(models.Model): username=models.CharField('用户名',max_length=30) #用户名 headImg=models.FileField('文件',upload_to='./upload')#文件名 def __str__(self): return self.username class Meta: ordering=['username']#排序风格username 同步数据库:Python manage.py makemigrations python manage.py migrate 3)设计视图(V) view.py: #coding=utf-8 from django.shortcuts import render,render_to_response from django import forms from django.http import HttpResponse from blog.models import * # Create your views here. class NormalUserForm(forms.Form): #form的定义和model类的定义很像 username=forms.CharField() headImg=forms.FileField() #在View中使用已定义的Form方法 def registerNormalUser(request): #刚显示时调用GET方法 if request.method=="POST": uf = NormalUserForm(request.POST,request.FILES)#刚显示时,实例化表单(是否有数据) if uf.is_valid():#验证数据是否合法,当合法时可以使用cleaned_data属性。 #用来得到经过'clean'格式化的数据,会所提交过来的数据转化成合适的Python的类型。 username = uf.cleaned_data['username'] headImg = uf.cleaned_data['headImg'] #write in database normalUser=NormalUser()#实例化NormalUser对象 normalUser.username = username normalUser.headImg = headImg normalUser.save()#保存到数据库表中 return HttpResponse('Upload Succeed!')#重定向显示内容(跳转后内容) else: uf=NormalUserForm()#刚显示时,实例化空表单 return render(request,'register.html',{'uf':uf})#只有刚显示时才起作用 配置urls.py: from django.conf.urls import url from django.contrib import admin from blog.views import * urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^register/$',registerNormalUser), ] 4)设计模板与表单(T)templates/register.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="
菲宇
2019/06/13
3.1K0
Django搭建blog网站(一)
一、前言 1.1.环境 python版本:3.6 Django版本:1.11.6 1.2.预览效果 最终搭建的blog的样子,基本上满足需求了。框架搭好了,至于CSS,可以根据自己喜好随意搭配。 二、
zhang_derek
2018/04/11
5.7K0
Django搭建blog网站(一)
相关推荐
性能优化三部曲之三——Node直出让你的网页秒开
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文