《浏览器工作原理与实践》笔记之从输入URL到页面展示发生了什么

从输入URL到页面展示发生了什么,大致过程如下 一、用户输入 浏览器进程接收到用户输入的 URL 请求,浏览器进程便将该 URL 转发给网络进程。 当用户输入关键字并键入回车之后,这意味着当前页面即将要被替换成新的页面,不过在这个流程继续之前,浏览器还给了当前页面一次执行 beforeunload 事件的机会,beforeunload 事件允许页面在退出之前执行一些数据清理操作,还可以询问用户是否要离开当前页面,比如当前页面可能有未提交完成的表单等情况,因此用户可以通过 beforeunload 事件来取消导航,让浏览器不再执行任何后续工作。 二、URL 请求过程 在网络进程中发起真正的 URL 请求。 网络进程接收到了响应头数据,便解析响应头数据,并将数据转发给浏览器进程。 建立TCP连接 服务器接收到请求信息后,会根据请求信息生成响应数据(包括响应行、响应头和响应体等信息),并发给网络进程。等网络进程接收了响应行和响应头之后,就开始解析响应头的内容了。 重定向 如果服务器响应行的状态码包含了 301、302 一类的跳转信息,浏览器会跳转到新的地址继续导航;如果响应行是 200,那么表示浏览器可以继续处理该请求。 响应数据类型处理 不同 Content-Type 的后续处理流程也截然不同。如果 Content-Type 字段的值被浏览器判断为下载类型,那么该请求会被提交给浏览器的下载管理器,同时该 URL 请求的导航流程就此结束。但如果是 HTML,那么浏览器则会继续进行导航流程。 由于 Chrome 的页面渲染是运行在渲染进程中的,所以接下来就需要准备渲染进程了。 三、准备渲染进程 浏览器进程接收到网络进程的响应头数据之后,发送“提交导航 (CommitNavigation)”消息到渲染进程。 Chrome 的默认策略是,每个标签对应一个渲染进程。但如果从一个页面打开了另一个新页面,而新页面和当前页面属于同一站点(根域名加上协议相同即为同一站点)的话,那么新页面会复用父页面的渲染进程。官方把这个默认策略叫 process-per-site-instance。 四、提交文档 渲染进程接收到“提交导航”的消息之后,便开始准备接收 HTML 数据(此过程即为“提交文档”阶段),接收数据的方式是直接和网络进程建立数据管道; 最后渲染进程会向浏览器进程“确认提交”,这是告诉浏览器进程:“已经准备好接受和解析页面数据了”。 浏览器进程接收到渲染进程“提交文档”的消息之后,便开始移除之前旧的文档,然后更新浏览器进程中的页面状态。 Read more…

《浏览器工作原理与实践》笔记之HTTP 请求和响应流程

浏览器端发起 HTTP 请求流程 构建请求 浏览器构建请求报文信息,构建好后,浏览器准备发起网络 请求行 GET /index.html HTTP1.1 发送请求行,就是告诉服务器浏览器需要什么资源,最常用的请求方法是 Get。 请求体 如果使用 POST 方法,那么浏览器还要准备数据给服务器,这里准备的数据是通过请求体来发送。 请求头 请求行之后,浏览器器以请求头形式发送其他一些信息,把浏览器的一些基础信息告诉服务器。比如包含了浏览器所使用的操作系统、浏览器内核等信息,以及当前请求的域名信息、浏览器端的 Cookie 信息,等等。 查找缓存 浏览器在发送请求之前先在浏览器缓存(是一种在本地保存资源副本,以供下次请求时直接使用的技术)中查询是否有要请求的文件。 当浏览器发现请求的资源已经在浏览器缓存中存有副本,它会拦截请求,返回该资源的副本,并直接结束请求,而不会再去源服务器重新下载。 好处如下: 缓解服务器端压力,提升性能(获取资源的耗时更短了); 对于网站来说,缓存是实现快速资源加载的重要组成部分。 如果查找缓存失败,则进入网络请求过程。 准备IP和端口号 IP 需要用到DNS来查找对应的IP地址 端口号 HTTP 协议默认是 80 端口,HTTPS协议是443端口。 等待TCP队列 不是说准备好了IP和端口号了就可以直接发送TCP连接的。 Chrome 有个机制,默认情况下同一个域名同时最多只能建立 6 个 TCP 连接,如果在同一个域名下同时有 10 个请求发生,那么其中 4 个请求会进入排队等待Pending状态,直至进行中的请求完成。 发送HTTP请求 一旦建立了 TCP 连接,浏览器就可以和服务器进行通信了。而 Read more…

《浏览器工作原理与实践》笔记之HTTP、TCP、DNS

因为浏览器使用 HTTP 协议作为应用层协议,用来封装请求的文本信息;并使用 TCP/IP 作传输层协议将它发到网络上,所以在 HTTP 工作开始之前,浏览器需要通过 TCP 与服务器建立连接。也就是说 HTTP 的内容是通过 TCP 的传输数据阶段来实现的。 PS: 图上的发送请求行和发送请求头是一个http请求过程 可以看出发送HTTP请求的第一步就是建立TCP连接,从《《浏览器工作原理与实践》笔记之数据包传输》我们了解到建立TCP连接是需要需要两点:IP和端口号 IP 由于 IP 地址是数字标识,比如极客时间网站的 IP 是 39.106.233.176, 难以记忆,但使用极客时间的域名(time.geekbang.org)就好记多了,所以基于这个需求又出现了一个服务,负责把域名和 IP 地址做一一映射关系。这套域名映射为 IP 的系统就叫做“域名系统”,简称 DNS(Domain Name System)。 浏览器还提供了 DNS 数据缓存服务,如果某个域名已经解析过了,那么浏览器会缓存解析的结果,以供下次查询时直接使用,这样也会减少一次网络请求。 端口号 通常情况下,如果 URL 没有特别指明端口号,那么 HTTP 协议默认是 80 端口,HTTPS协议是443端口。 知道了发送请求必须的IP和端口号之后我们就可以建立TCP连接了。

《浏览器工作原理与实践》笔记之数据包传输

从数据包如何送达主机、主机如何将数据包转交给应用和数据是如何被完整地送达应用程序这三个角度来为你讲述数据的传输过程。 IP:把数据包送达目的主机 下面我们一起来看下一个数据包从主机 A 到主机 B 的旅程: 上层将含有“极客时间”的数据包交给网络层; 网络层再将 IP 头附加到数据包上,组成新的 IP 数据包,并交给底层; 底层通过物理网络将数据包传输给主机 B; 数据包被传输到主机 B 的网络层,在这里主机 B 拆开数据包的 IP 头信息,并将拆开来的数据部分交给上层; 最终,含有“极客时间”信息的数据包就到达了主机 B 的上层了。 数据包的传输是通过IP协议进行的,那这些数据包怎么知道已经传个哪个应用程序呢?我们接着往下看 UDP:把数据包送达应用程序 每个想访问网络的程序都需要绑定一个端口号 所以我们通过端口号 UDP 就能把指定的数据包发送给指定的程序了,所以 IP 通过 IP 地址信息把数据包发送给指定的电脑,而 UDP 通过端口号把数据包分发给正确的程序。和 IP 头一样,端口号会被装进 UDP 头里面,UDP 头再和原始数据包合并组成新的 UDP 数据包。UDP 头中除了目的端口,还有源端口号等信息。 所以前面提到的三层传输模型需要额外再加一层传输层了 下面我们一起来看下一个数据包从主机 A 旅行到主机 B Read more…

《浏览器工作原理与实践》笔记之浏览器进程

浏览器从单进程浏览器时代进入多进程时代 Q1:最新的浏览器架构图 Q2:浏览器打开一个tab页,一般会有几个进程? 浏览器主进程 GPU进程 网络进程 多个渲染进程。如果2个页面属于同一站点的话,并且从a页面中打开的b页面,那么他们会公用一个渲染进程 多个插件进程 如果页面里有iframe的话,iframe也会运行在单独的进程中! 如果页面里有插件,同样插件也需要开启一个单独的进程! 如果你装了扩展的话,扩展也会占用进程 一般来说最低是上面的前4个。 Q3:多进程浏览器是怎么解决单进程浏览器时代的不流畅的问题 JavaScript 也是运行在渲染进程中的,所以即使 JavaScript 阻塞了渲染进程,影响到的也只是当前的渲染页面,而并不会影响浏览器和其他页面,因为其他页面的脚本是运行在它们自己的渲染进程中的。所以当我们再在 Chrome 中运行上面那个死循环的脚本时,没有响应的仅仅是当前的页面。 Q4:如今的多进程架构,我偶尔还会碰到一些由于单个页面卡死最终崩溃导致所有页面崩溃的情况,请问这是什么原因呢 通常情况下是一个页面使用一个进程,但是,有一种情况,叫"同一站点(same-site)",具体地讲,我们将“同一站点”定义为根域名(例如,geekbang.org)加上协议(例如,https:// 或者http://),还包含了该根域名下的所有子域名和不同的端口,比如下面这三个: https://time.geekbang.org https://www.geekbang.org https://www.geekbang.org:8080 都是属于同一站点,因为它们的协议都是https,而根域名也都是geekbang.org。你也许了解同源策略,但是同一站点和同源策略还是存在一些不同地方,在这里你需要了解它们不是同一件事就行了。 Chrome的默认策略是,每个标签对应一个渲染进程。但是如果从一个页面打开了新页面,而新页面和当前页面属于同一站点时,那么新页面会复用父页面的渲染进程。官方把这个默认策略叫process-per-site-instance。 直白的讲,就是如果几个页面符合同一站点,那么他们将被分配到一个渲染进程里面去。 所以,这种情况下,一个页面崩溃了,会导致同一站点的页面同时崩溃,因为他们使用了同一个渲染进程。 Q5:为什么会出现同一站点时新页面复用父页面的渲染进程的情况? 因为在一个渲染进程里面,他们就会共享JS的执行环境,也就是说A页面可以直接在B页面中执行脚本。因为是同一家的站点,所以是有这个需求的。 Q6:浏览器主进程负责将渲染进程生成的图片显示在ui上面,就是说渲染进程输出的最终是图片,浏览器显示的是图片,那么为什么浏览器中鼠标能选中文字?如果页面是图片的话文字是选不中的啊,这里面的机制又是怎样的? 点击鼠标选中文字的时候,这些消息会传递到渲染进程,渲染进程再合成选中文字的状态,然后更新图片! 本文截取自《浏览器工作原理与实践》01 | Chrome架构:仅仅打开了1个页面,为什么有4个进程?

浏览器滚动条hover时变粗、改变颜色

今天应UED的要求对项目的滚动条进行美化,原生的滚动条虽然很使用,但确实不美观。 用了一些css美化后 ::-webkit-scrollbar{ height: 9px; width: 9px; } ::-webkit-scrollbar-thumb { border-radius: 10px; background-color: rgba(157, 165, 183, 0.4); } 好看多了 但是我们发现了一个问题,就是在滚动条变细之后导致我们想要用鼠标拖动滚动条时有时有些困难。 无意中发现滚动条实际上是由边框和背景色共同组成 于是我们就有了思路,将滚动条的border设置成透明的,只有鼠标hover时才将滚动条的border背景色设置出来 在网上搜索解决方案,无意间发现这篇文章 滚动条悬浮改变颜色大小 里面提到 又很偶然的发现background-clip: padding-box,设置该属性后背景延伸至内边距(padding)外沿,不会绘制到边框处,也就是说设置该属性后,背景将被限制在内容和边距之内,边框背景不会改变。 我们参考进行了下面的改动 完整代码 ::-webkit-scrollbar{ height: 9px; width: 9px; } ::-webkit-scrollbar-thumb { border-radius: 10px; border-style: dashed; border-color: transparent; border-width: 2px; background-color: rgba(157, 165, 183, 0.4); Read more…

对React Hooks的Capture value特性的理解

之前我的项目里面很多功能都是用的事件驱动,所以下面的实例也会更多地使用监听事件的回调函数。 我们先看下测试代码 const {useEffect ,useState, useRef, useMemo} = React; const {render} = ReactDOM; const eventBus = new EventEmitter(); function ListenButton() { const [started, setStarted] = useState(false); const [score, setScore] = useState(0); function onStartedClick() { setStarted(!started); } function onClick() { setScore(score + 1); } function onBouns() { setScore(score + 2); } Read more…

WordPress上传图片出现“图像后期处理失败,请将其缩小到2500像素并重新上传”

今天在上传图片的时候发现了这个报错“图像后期处理失败,请将其缩小到2500像素并重新上传”,如果是英文版的话,就会报错“Post-processing of the image failed. If this is a photo or a large image, please scale it down to 2500 pixels and upload it again”。显然很容易想到这是因为图片过大导致的,现在的手机照片像素都那么高了,2M确实太少了,压缩图片也够麻烦的。 我们需要进行下列步骤修改下上传文件的大小上限: 修改php配置文件php.ini 默认php上传文件的大小是2M了,我们可以在后台的“媒体”——“上传新媒体文件”处看到 php.ini文件一般位于/etc/php.ini,我们需要在里面加上 upload_max_filesize = 64M post_max_size = 64M max_execution_time = 300 修改wordpress的functions.php 如果修改了上面的php.ini可以直接跳过此步骤 @ini_set( 'upload_max_size' , '64M' ); @ini_set( 'post_max_size', '64M'); @ini_set( 'max_execution_time', Read more…

原创的几个前端校招面试题

鉴于太多新入行的朋友理论知识太扎实,简历太精彩,特出了几个手写题目,不求每个都作对,面试过程都是先问理论,如果答的不错的话再要求写代码。 变量提升 console.log(1, test); var test = 1; console.log(2, test); function test(){ console.log(3, test); } test(); 实测没有全部做对的,第三个console不会打印,因为test()会报错 内存堆栈 var a = 1; var b = a; var b = 100; console.log(a, b); var aa = [22, 33] var bb = aa; bb[0] = 44; console.log(aa, bb) for循环 分别打印 0 1 Read more…

react router页面跳转二次确认弹框及样式、业务逻辑自定义

我们在编辑页面时如果需要跳走通常会需要给用户提示,react router本身已经给了我们这样的功能,我们先看看怎么使用。 初见二次确认弹框 // App.jsx const App = () { return ( <BrowserRouter> <div> <ul style={{marginTop: '10px'}}> <li> <Link to='/'>Home</Link> </li> <li> <Link to='/write'>Write</Link> </li> </ul> <Switch> <Route exact path='/'> </Route> <Route path='/write' strict={true} forceRefresh={true} component={WriteMail}> </Route> </Switch> </div> </BrowserRouter> ); } export default App; 在WriteMail组件里面我们加上Prompt组件并且设置when为true,就会有二次确认弹框了,也就是从/write页面跳转时会需要进行确认 // WriteMail.jsx const WriteMail Read more…