webkit技术内幕读书笔记 (四)
资源缓存
资源缓存的目的是为了提高资源使用的效率,其基本思想是建立一个资源的缓存池,当需要请求资源的时候先去资源池查找是否有相应的资源,如果没有则向服务器发送请求,webkit收到资源后将其设置到该资源类的对象中去,以便于缓存后下次使用,webkit从资源池中查找资源的关键字是URL,URL标记了资源的唯一性。
以上说明一个问题,如果ulr不同,就算内容相同也会被重新请求。
资源加载
鉴于从网络获取资源时一个非常耗时的过程,通常一些资源的加载是异步执行的,也就是说资源的获取和加载不会阻碍 当前 WebKit的渲染过程,例如图片、CSS文件。当然,网页也存在某些特别的资源会阻碍主线程的渲染过程,例如 JavaScript 代码文件。这会严重影响 WebKit 下载资源的效率,因为后面可能还有许多需要下载的资源,WebKit会怎么做?因为主线程被阻碍了,后面的解析工作没办法继续往下进行,所以对于 HTML 网页中后面使用的资源也没有办法知道并发送下载请求。当遇到这种情况的时候,WebKit的做法是这样的:当前的主线程被阻碍时。WebKit会启动另外一个线程去遍历后面的HTML页面,收集需要的资源URL,然后发送请求,这样就可以避免被阻碍。与此同时,WebKit 能够并发下载这些资源,甚至并发下载 JavaScript 代码资源。
为了验证以上是否正确,在本地搭了个服务器测试,其中有一个index.html页面,和一个服务器脚本,服务器脚本用来延迟加载js。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<h2>h2</h2>
<script src="http://localhost:8081/index.js"></script>
<h3>h3</h3>
<img src="test/images/0.png" alt="">
<img src="test/images/1.png" alt="">
<img src="test/images/2.png" alt="">
<script src="index.js"></script>
<script>
console.log("ok");
</script>
</body>
</html>
nodejs脚本 index.js
var http = require("http");
http.createServer(function(req,res){
}).listen(8081);
index.html请求了8081端口的一个js脚本,但是我始终不给它响应。
可以看到加载js的那一块始终是一个pending状态,但是在js后面的资源还是被下载了,也就是说webkit确实是开了多个线程去下载资源的,但你也可以看到,它虽然是开了多个线程去下载资源,但是并没有去执行后面的代码,如下图
从另外一个方面也可以看出它没有去执行后面的代码,我在index.html中写了这么一段代码<script src="index.js"></script>
假如说它执行了,那么应该报错才对,因为这段代码的内容就是那个nodejs中的,如果我返回内容,效果就是下面这样
也就是说,虽然资源webkit可能开多个线程去下载,但是执行代码,始终用的是一个线程,对于执行javascript代码使用一个线程执行,还算好理解,因为某些js文件可能依赖于其他的js文件,如果说使用多线程,这必然是一个比较麻烦的问题,另外如果某些js文件必须早于其他文件执行,那么多线程依然还是个问题,对于图片和dom大概也是同样的道理吧,如果说下载下来的图片,马上就去显示,那如果说我在前面的js中给body加了一个display:none;那么你说是这个图片是显示呢还是不显示呢?不能因为前面的js堵塞了后面的代码执行,你就乱显示吧,这也是多线程了一些烦恼吧。
资源的生命周期
同CachedResourceLoader对象一样,资源池也属于HTML文档对象,由于资源池不能无限大,因此要用相应的机制来替换其中的资源,从而加入新的资源,这种机制采用的算法为LRU(最近最少使用)算法。对于打开网页刷新当前页面的场景,对于某些资源,webkit需要直接重新发送请求,要求服务器端将内容重新发送过来,但对于大多数资源,Webkit则可以利用HTTP协议减少网络负载,在HTTP协议中对此有规定,游览器可以发送消息确认是否需要更新,如果有则游览器重新获取该资源,否则就需要利用该资源。
webkit的做法如下,首先判断资源是否在资源池中,如果在则发送一个HTTP请求给服务器,说明该资源在本地的一些信息,例如修改时间等,服务器根据该信息进行判断,如果没有更新则返回状态码304表示不需要更新,直接利用资源池中的资源,否则webkit申请下载最新的资源内容。
DNS预取和TCP预连接
一次DNS查询的平均时间大概在60~120ms之间或者更长,而TCP的三次握手时间大概也是几十毫秒或者更长,看似是一个很短的时间,但是相对于网页的渲染来说,这是一个相当长的时间,如何有效的缩短这段时间,Chromium给出了自己的解决方案—DNS预取和TCP预连接。
首先讲一下DNS预取,他的主要思想就是利用现有的DNS机制,提前解析网页中可能的网络连接。具体来说,就是当用户正在浏览当前网页的时候,Chromium提取网页中的超链接,将域名抽取出来,利用比较少的CPU和网络带宽来解析这部分域名或IP地址,这样一来,用户根本感觉不到这一过程。但是当用户单击这些链接的时候,由于已经提前做好了DNS解析,可以节省不少时间,特别是对于域名解析比较慢的时候,效果尤其明显。(DNS预取技术针对多个域名采取并行处理的方式,每个域名的解析均是由新开启的一个线程来处理的,结束后此线程即退出)
当然,我们也可以显式指定预取哪些域名来让Chromium解析,这非常直接了当。特别是对于那些需要重定向的域名,具体做法如下:
<link rel="dns-prefetch" href="http://this-is-a-dns-prefetch-example.com">。
DNS预取技术不仅应用于网页中的超链接,当我们在地址栏中输入地址后,候选项同输入的地址很匹配的时候,在我们敲下回车键获取该网页之前,Chromium已经开始使用DNS预取技术解析该域名了。
接下来是TCP预连接,Chromium使用追踪技术来获取用户从什么网页跳转到另外一个网页,可以利用这些数据,一些启发式的规则和其他暗示来预测用户下面回单击什么超链接,当有足够的把握的时候,他便会DNS预取,更进一步,还可以预先简历TCP连接。听起来是不是特别6?不错,Chromium就是这么6!同DNS预取技术一样,追踪技术不仅应用于网页中的超链接,当用户在地址栏中输入地址的时候,也同样适用!
webkit技术内幕读书笔记 (四)的更多相关文章
- webkit技术内幕读书笔记 (一)
本文部分摘录自互联网. Chromeium与Chrome Chromium是Google为发展自家的浏览器Google Chrome而打开的项目,所以Chromium相当于Google Chrome的 ...
- webkit技术内幕读书笔记 (二、三)
可视区和网页 通常网页比屏幕的可视区面积要大,因此当网页内容在可视区中放不下时,一般浏览器会提供滚动条. 从URL到构建完DOM树的过程 当用户输入网页URL的时候,WebKit调用其资源加载器加载该 ...
- 深入理解linux网络技术内幕读书笔记(四)--通知链
Table of Contents 1 概述 2 定义链 3 链注册 4 链上的通知事件 5 网络子系统的通知链 5.1 包裹函数 5.2 范例 6 测试实例 概述 [注意] 通知链只在内核子系统之间 ...
- Struts2技术内幕 读书笔记三 表示层的困惑
表示层能有什么疑惑?很简单,我们暂时忘记所有的框架,就写一个注册的servlet来看看. index.jsp <form id="form1" name="form ...
- Struts2技术内幕 读书笔记一 框架的本质
本读书笔记系列,主要针对陆舟所著<<Struts2技术内幕 深入解析Strtus2架构设计与实现原理>>一书.笔记中所用的图片若无特殊说明,就都取自书中,特此声明. 什么是框架 ...
- 深入理解linux网络技术内幕读书笔记(三)--用户空间与内核的接口
Table of Contents 1 概论 1.1 procfs (/proc 文件系统) 1.1.1 编程接口 1.2 sysctl (/proc/sys目录) 1.2.1 编程接口 1.3 sy ...
- Kafka技术内幕 读书笔记之(四) 新消费者——消费者提交偏移量
消费组发生再平衡时分区会被分配给新的消费者,为了保证新消费者能够从分区的上一次消费位置继续拉取并处理消息,每个消费者需要将分区的消费进度,定时地同步给消费组对应的协调者节点 .新AP I为客户端提供了 ...
- Kafka技术内幕 读书笔记之(四) 新消费者——心跳任务
消费者拉取数据是在拉取器中完成的,发送心跳是在消费者的协调者上完成的,但并不是说拉取器和消费者的协调者就没有关联关系 . “消费者的协调者”的作用是确保客户端的消费者和服务端的协调者之间的正常通信,如 ...
- Kafka技术内幕 读书笔记之(四) 新消费者——新消费者客户端(二)
消费者拉取消息 消费者创建拉取请求的准备工作,和生产者创建生产请求的准备工作类似,它们都必须和分区的主副本交互.一个生产者写入的分区和消费者分配的分区都可能有多个,同时多个分区的主副本有可能在同一个节 ...
随机推荐
- 20170831工作日记--自定义View学习
学习了LayoutInflater的原理分析.视图的绘制流程.视图的状态及重绘等知识,按类型来划分的话,自定义View的实现方式大概可以分为三种,自绘控件.组合控件.以及继承控件.那么下面我们就来依次 ...
- js-倒计时原理
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> ...
- RxSwift学习笔记1:RxSwift的编程风格
第一天:简单体验与RxSwift的编程风格 import UIKit//导入Rx相关框架 import RxSwift import RxCocoa struct Music { let name:S ...
- Objective-C与Swift混编
1,创建项目(比如你先选择Objective-C) 2,项目创建成功后接着创建一个swift类 3,Xcode会弹出提示框问你需不需要创建桥接文件(桥接文件的名称默认为:项目名称-Bridging- ...
- vue项目webpack中Npm传递参数配置不同域名接口
项目开发中,前端在配置后端api域名时很困扰,常常出现:本地开发环境: api-dev.demo.com测试环境: api-test.demo.com线上生产环境: api.demo.com, 这次是 ...
- .Net Core Razor 预编译,动态编译,混合编译
预编译 预编译是ASP .Net Core的默认方式.在发布时,默认会将系统中的所有Razor视图进行预编译.编译好的视图DLL统一命名为 xxx.PrecompiledViews.dll 或者 xx ...
- 【转】JS中的call()和apply()方法
原文:http://uule.iteye.com/blog/1158829 1.方法定义 call方法: 语法:call([thisObj[,arg1[, arg2[, [,.argN]]]]]) ...
- Web 前端 注意知识点
一. 前端使用技巧: 1. button的用法.在使用按钮时可以自由在内设置style属性,来改变形态.可以给予type=sbumit提交属性. 2. 各种使用符号: # <!--小于 大于 ...
- .NET Core 从1.1升级到2.0记录(Cookie中间件踩坑)
.NET Core 2.0 新时代 万众瞩目的.NET Core 2.0终于发布了,原定于9.19的dotnetconf大会的发布时间大大提前了1个月,.NET Core 2.0/.NET Stand ...
- Unable to preventDefault inside passive event listener due to target being treated as passive?
使用滚动时候,新版google浏览器,会弹出如下的警告. 解决方法,可以加上* { touch-action: none; } 这句样式去掉. 其原因:https://developers.googl ...