一项新技术的来临,总是自上而下的,从标准推出到软硬件支持再到实施,然后普及,这中间总要经历漫长的更新之路。本文我们跨过慢慢长夜,直接讨论假如HTTP/2已经普及,我们前端跟现在会有哪些不同,也许你会觉得太操之过急,没必要这么早开始讨论,然而回看历史,各种技术总会在我们不经意间闯入我们的工作,更新我们的生活,与其措手不及不如提早部署,只有心怀远方我们才能走的更远。

如果不清楚什么是 HTTP/2 的可以先了解下,前面有一篇图文并茂的介绍HTTP/2的文章 传送门

现状

去年(2015年5月)HTTP/2标准正式发布,各大浏览器,服务器厂商都开始大面积支持这一标准,国内外各大应用网站也都开始纷纷踏入HTTP/2的阵营,Facebook、Google、Twitter、国外亚马逊(部分请求)、天猫(部分请求)、淘宝(部分请求),还有一些小型站点比如 ISUX 等。

一些大型公司,因为架构体系原因导致迁移带来的阵痛,拖累了升级HTTP/2的进度,有心无力,反而一些小型网站,架构合理的公司升级起来更迅速一些,提早体验到了HTTP/2带来的快感。

现在软硬件都已基本到位,“趟雷”的已经探好了路,就等后续大军杀到。买房子的时候,都说早买早享受,HTTP/2也一样,房子买晚了,HTTP/2你还要再等么,你要做的其实就是尽早升级尽快享受。

HTTP/2已经普及

也许HTTP/2真正全面普及,可能还得一两年,或者是三四年,那么我就直接穿越到未来的一天,假设HTTP/2已经普及了,那么很快会有很多问题摆在我们面前:以前的架构还需要么?如何组织代码更能合理支持HTTP/2?我们十几年的优化总结还有用么?雅虎军规还是我们的优化的标准么?

在讨论这之前我们再来回顾下,HTTP/2给我们提供了什么。

HTTP/2给我们的好处

  • 多路复用 :一次TCP握手,多个同域并行请求,请求和响应同时发送接受,然后再拼装组合,不阻塞;
  • 优先级和依赖性(Priority) :可以请求的时候告知服务器端,资源分配权重,优先加载重要资源;
  • 服务器推送(Server Push) :根据客户端需求,服务端主动推送资源,减少请求耗时;

概念网上大把,我们直接用几个例子来分析,把概念直接体现在实例中:

多路复用

Demo HTTP/2 和 HTTP1.1 图片请求对比

示例分别用169张图片拼合成一整张大图,第一组图片请求为HTTP1.1,第二组请求为HTTP/2,下面我截取的加载过程的动画。

HTTP1.1 vs HTTP/2 请求速度
http1 vs http2

同时导出了 http1.1-images.harhttp2-images.har 文件,我们借助第三方服务HAR Viewer 来看下,请求细节:

HAR文件 是以.har结尾的JSON文件,用于记录了HTTP请求的详细信息。这里有详细介绍,可以在Chrome中开发者工具的Network中点右键导出.har文件。

下图就是HAR文件分析的截图:

HTTP1.1
http1.1

上图为HTTP1.1的图片请求,请求基本上是6个一组,然后6个完成后再 串行请求 下一组。

HTTP/2
http2

从上面的部分截图,可以清晰看到,所有请求基本都是并行请求,由于数据发送量较大,所以会有“等待”,这里的等待应该是数据流在客户端或服务器端重新组合的过程,正是因为这样所以单个请求时间相对更长。但是就整体速度来说 HTTP/2 为1.53s, HTTP1.1为 2.47s。速度快了近40%

http2

上面这张图也是HTTP/2的一部分,从另一面也可以体现出,并行请求的短板,就是木桶理论。所以请求尽量做到细粒度,能更快返回数据。

PS:当然我只截取了比较能突出差别的图,具体的完整版可以点进HAR Viewer,然后拖进去我们上面提供的har文件。

这就是HTTP/2为我们带来的最大的好处多路重复

服务器推送(Server Push)

Demo 普通加载 & Demo Server Push

示例分别用Server Push推送,和传统的加载,带来的性能上的差异,同时我也导出了两个HAR文件,如果需要可自行下载 serverpush.harnomalrequest.har

下面是这两个文件的请求截图(下面是Server Push, 上面是普通HTTP/2的请求):

server push

HTTP/2 Server Push 和 普通请求相比,去掉了请求阶段,直接返回数据(Content Download),数据获取速度更快,而且push中可以嵌入逻辑,并且请求还可以进行缓存。

贴一小段代码,下面的代码为请求接口的时候,主动推送zepto代码给客户端的核心代码:

1
2
3
4
5
6
7
8
9
10
11
router.get('/serverpush', function (ctx, next){
var zepto = fs.readFileSync(resolve(root, 'public/js/zepto.js'), { encoding: 'UTF-8' })
var html = fs.readFileSync(resolve(root, 'public/item2_1.html'), { encoding: 'UTF-8' })
ctx.res.push('/zepto.js', options, function(err, stream){
if (err) return;
zlib.gzip(zepto,function(err, buf){
stream.end(buf)
})
});
ctx.body = html
})

这里可以查看完整的Server Push代码

关于优先级和依赖性(Priority)

优先级的设置可以看下这一篇文章,通过设置请求资源的Pripority,达到资源获取的优先级。

没有设置Pripority
pripority

设置CSS 和 JS 的 Pripority后
![pripority]//img.aotu.io/Fr9ScV9DSWoyn8yr0RWvbpWhQq30)

设置Pripority后,CSS 和 JS 明显速度更快了,但是代价是牺牲了图片的部分请求的速度。

通过上面的示例,牛B闪闪的HTTP/2已经在屏幕上熠熠生辉了。

那么回过头来再看看我们以前针对HTTP1.1的优化,我觉得很多其实都是应对HTTP1.1不足的HACK,HTTP/2中这些都已经不是问题了,所以HACK可以去掉了,比如下面这些。

雪碧图(Sprite)

这里同样我写了一个测试示例 Demo 雪碧图 & Demo 没有雪碧图,如下图上面为使用雪碧图的页面请求, 下面是普通的请求页面。
Sprite

由于木桶理论,在非雪碧图请求中,由于最后返回速度决定于那个最慢的请求,所以非雪碧图单张524B的文件速度,跟雪碧图6.9K速度比,还慢一些,虽然如此,我们再看onload事件触发时间,因为多路复用的特性,虽然请求超过4倍但是请求总时长并不是多4倍,而是多了119ms(1-2张图片的请求时长),而且根据请求更多其实差距不会体现在请求的多少,而只会体现在请求的响应时间和下载数据的大小,而雪碧图占用的请求应该都是很小的,所以合并与否其实不明显,再考虑到雪碧图的维护成本,其实就HTTP/2来说并不推荐再使用雪碧图了。(不过为了兼容HTTP1.1,其实现阶段多版本并存的时候还是建议保留,不用再单独处理逻辑)

HTTP1.1中,所有为了减少请求而做出的HACK,在HTTP/2中都已经不再是性能优化考虑的主要点了。

分域名

HTTP1.1时代,我们经常会用多个域名来做请求优化,因为浏览器同域名下会有并行请求数限制(根据浏览器不同2-8个,比如IE6只有两个),然而DNS解析又得额外花时间,所以以前对域名的个数还需要根据各自网站找一个平衡点。HTTP/2就不用理会这个了,因为多路复用,并行请求不再是瓶颈,收敛了域名后还能减少DNS解析时间,所以HTTP/2中我们不用再细分域名了。

接口请求

HTTP1.1的时候,我们经常会根据当前的页面,将请求合并成一个。HTTP/2中可以更细粒度的组合你的接口,不用再根据某个页面所需数据,来组合一个专门的无意义的接口了(不用合并请求),不怕请求多,就怕单个请求太慢。

内联资源

有人说Server Push就是另外一种形式的内联,其实不是,内联太Low了,完全无法跟它来比较。

首先我们来回顾下,HTTP1.1时代,我们为什么要内联,因为我们希望减少请求,我们为了加快首页的渲染速度,甚至会把首页第一屏的样式内联到HTML中,一起返回,加速首屏渲染。然而当有人想改动首屏任何内容,无论多小都得重新替换掉整个页面。

在HTTP/2下我们可以通过推送的方式给你想要的资源,跟你的HTML请求一块儿返回给你,不仅如此,push的内容还可以进行缓存,多页面共享。

兼容

先来看下兼容和各版本客户端占有率统计

数据来自caniuse
can i use

PC浏览器占有率
数据来自百度统计
pc

IOS & Andorid 操作系统版本占有率
数据来自友盟 2016年 6月5日统计数据,红色为支持版本
占有率

结论:PC 端 Chrome 占有率已经近 40%,移动 Android5.0 以上占 26%,IOS9.2 占 60% 以上,所以保守估计,至少现阶段升级HTTP/2,就已经能保证 1/3 的人能享受到HTTP/2带来的快感,而且这个数字随着时间会快速增长。
同时HTTP是支持向前兼容的,如果你的浏览器不支持HTTP/2可以降级成HTTP1.1,而且服务端也可以通过请求来判断客户端是不是支持HTTP/2,如此一来我们可以通过请求来返回HTTP/2版本的网站。这样就能尽量让更多人体验到HTTP/2的一些特性了,并且不影响其他人的使用。

以前当我们无法快速提升网络速度,无法改变一些硬件上的性能,能做的可能只有代码阶段,然而现在有了一种强劲的性能提升方案,那就是HTTP/2,也是目前性价比最高的性能提升方案了。

当然,如果你还是很纠结HTTP/2的兼容性,推荐另一个HTTP协议 SPDY,虽然HTTP/2的出现,迟早会替换掉SPDY,但是作为HTTP/2的前身,兼容性会更好,比如淘宝,天猫都已经支持SPDY了,个人觉得替换SPDY就是时间问题,所以还是推荐从HTTP/2开始吧。

不过既然提到就先看看兼容性:
兼容性

SPDY不是本文重点就推荐一些资料:
SPDY介绍
nginx 配置SPDY
node-spdy 一个node库支持HTTP/2 和 SPDY
HTTP/2 is here! Goodbye SPDY? Not quite yet

本文的Demo 及 测试代码

代码地址
测试Demo

本文参考资料

nghttp2.org
很棒的介绍HTTP/2的文章
HAR Viewer 最棒的har预览服务
Jerry Qu 的博客
HTTP/2版本发布页