现代的we应用的平均请求数为90
时间与用户感觉:
12博体育,超过1s,12bet,用户心思就会转移到其他任务,超过10s,除非有反馈,否则用户基本上会终止任务
http请求由很多独立的阶段组成:DNS解析,TCP握手,TLS协商(必要时),12博体育,发送HTTP请求
web应用主要有三个任务:取得资源,页面布局和渲染,Javascript执行
更多的带宽不大重要,延迟才是性能瓶颈,如下图所示
影响用户体验的一些方面:
Navigation Timing API:可以查询到DNS和TCP连接时间
window.performance对象
function init() {
// 1.存储时间戳
performance.mark("startTask1");
// 2.执行应用代码
applicationCode1();
performance.mark("endTask1");
logPerformance();
}
function logPerformance() {
var perfEntries = performance.getEntriesByType("mark");
// 3. 迭代和记录用户计数数据
for (var i = 0; i < perfEntries.length; i++) {
console.log("Name: " + perfEntries[i].name +
" Entry Type: " + perfEntries[i].entryType +
" Start Time: " + perfEntries[i].startTime +
" Duration: " + perfEntries[i].duration + "n");
}
// 4.记录当前页面的Navigation Timing对象
console.log(performance.timing);
}
核心优化策略:
优化技术:
除了页面结构的优化,还可以在文档中嵌入提示,以触发浏览器的优化机制:
<!-- 预解析特定域名 -->
<link rel="dns-prefetch" href="//hostname_to_resolve.com">
<!-- 预取得页面后面要用到的关键性资源 -->
<link rel="subresource" href="/javascript/myapp.js">
<!-- 预取得将来导航要用到的资源 -->
<link rel="prefetch" href="/images/big.jpeg">
<!-- 根据用户下一个目标的预测,预渲染特定页面 -->
<link rel="prerender" href="//example.org/next_page/">
增加的特性:
针对网络的优化:
每个TCP连接都要有三次握手,要经历一次客户端与服务器间完整的往返,持久连接就是HTTP请求结束后并不会立刻关闭HTTP连接,这样下一次的请求就不需要再经历三次握手。
通过首部
Connection: Keep-Alive
单独通过tcp连接获取html和css文件的情况如下图
通过持久连接获取html和css文件的情况如下图
N次请求节约N-1次RTT
持久连接可以重用已有的连接,但是必须严格满足先进先出(FIFO)的队列顺序:发送请求,等待响应完成,再次发送客户端队列中的下一个请求。
HTTP管道将FIFO队列从客户端(请求队列)迁移到服务器(响应队列),串行
即使客户端同时发送两个请求,而且css资源先准备完毕,服务器也会先发送html响应,再交付css,这种情况叫队首阻塞
问题:
大多数现代浏览器,都支持每个主机打开6个连接(对于同一个域名),这一限制主要是防止客户端消耗掉服务器的所有资源
6个连接的限制,也是符合公平原则的,保证每个客户端都有机会与服务器建立连接,不会因为某些客户端占用过多的连接,从而使得有些客户端得不到连接
目前平局每个页面都包含90多个独立的资源,如果都来自同一个主机,就会导致排队,可以将资源分散到多个子域名:{share1,share2}.example.com
,由于主机名不一样了,就可以突破浏览器连接的限制,实现更高的并行能力。
缺点:每个新主机名都要求有一次额外的dns查询(对移动客户端影响更大),每多一个套接字都会多消耗两端的资源,而且必须手工分散这些资源托管于多个主机上
http请求都会携带额外的500~800字节的http元数据:用户代理字符串,很少改变的首部,缓存指令等。此外还有一大块的Cookie
拼接:将多个javascript或css文件合并为一个文件 拼合:把多张图片组合成一个更大的复合的图片
浏览器是以递增的方式处理html的,但是对于javascript和css的解析和执行,则要等到整个文件下载完成,javascript和css处理器都不允许递增式执行
前面这段话理解并不难,html只是标记,各个tag比较独立,前面的tag和后面的tag不会互相影响;
但是javascript有声明提升机制,定义在文件后面的方法,可以在文件的前面就调用;
而css有选择器优先级的限制,只有编译整个css文件才能综合的确定某个元素的样式
嵌入资源是一种十分流行的优化方法,把资源嵌入文档可以减少请求的次数,比如javascript和css代码可以通过script和style标签直接嵌入页面中,图片甚至是音频或pdf文件,可以通过数据URI(data:[mediatupe][;base64],data
)的方式嵌入页面中
缺点:
一般只考虑嵌入1~2kb以下的,最好是只在个别页面中使用,并且不是经常更新
spdy是http 2.0的催化剂,使得页面加载时间提高了50%以上
http 2.0是http 1.1的拓展而不是代替,http 2.0增加了新的二进制分帧数据层,兼容1.1
通过增加二进制分帧层来提高性能,将传输的消息分割为更小的消息和帧,并采用二进制编码
所有的http 2.0通信都在一个连接上完成,这个连接可以承载任意数量的双向数据流,每个数据流以消息的形式发送,而消息由一或多个帧组成,这些帧可以乱序发送,然后根据每个帧首部的标识符重新组装
对这三个概念的理解
http 1.x 会导致队首阻塞,http 2.0 突破了这个限制,客户端和服务器可以将 http 消息分解为互不依赖的帧,然后乱序发送,最后再在另一端将他们重新组合起来,提高了 tcp 连接的效率
每个流都带有一个31比特的优先级:
服务器可以根据优先级,对于不同的流采用不同的处理策略,优先级高的优先分配资源
所有http 2.0连接都是持久化的,服务器与客户端只需要一个连接即可
每个来源一个连接显著减少了资源占用:套接字管理工作量少了,内存占用减少了,连接吞吐量减少了,好处:
http 2.0流量控制机制:
WINDOW_UPFATE
帧更新,这个字段指定了流ID和窗口大小递增值服务器推送就是服务器可以对一个客户端的请求发送多个响应,就是除了对最初的请求响应外,服务器还可以额外向客户端推送资源,而不需要客户端明确请求
http 2.0会压缩首部元数据:
通过Upgrade
机制来协调适当的协议:
发送升级到http 2.0的请求
GET /page HTTP/1.1
Host: server.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: HTTP/2.0 // 升级到http 2.0
HTTP2-Settings: (SETTINGS payload) // http 2.0 settings净荷的base64 url编码
服务器不支持http 2.0,返回http 1.1响应
HTTP/1.1 200 OK // 不支持http 2.0
Content-length: 243
Content-type: text/html
(... HTTP 1.1 response ...)
支持http 2.0告诉客户端可以用http 2.0
HTTP/1.1 101 Switching Protocols // 接收http 2.0升级,切换到新的分帧
Connection: Upgrade
Upgrade: HTTP/2.0
(... HTTP 2.0 response ...)
如果客户端保存了关于 http 2.0 的支持信息,可以直接发送 http 2.0 分帧,而不必使用 Upgrade 机制
http 2.0规定了如下帧类型
由两种情况会发起新流:
HEADERS
帧来发起新流,这个帧包含带有新流ID的公用首部,可选的31位优先值,以及一组http键值对首部PUSH_PROMISE
帧来发起推送流,这个帧与HEADERS
帧等效,但它要包含“要约流ID”,没有优先值数据格式基本的二进制分帧结构一样,没有优先级标识
DATA帧的长度字段决定每帧净荷最多可达2^16-1(65535)字节,但是为了减少队首阻塞,http 2.0标准要求DATA帧不要超过2^14-1(16383)字节,长度超过阀值就会分帧发送