当前位置: 首页 > 科技观察

前端应该懂的浏览器工作原理你懂吗?_0

时间:2023-03-16 19:28:27 科技观察

前言在我们面试的时候,面试官经常会问这样一个问题,就是从在浏览器地址栏输入网址到显示页面,浏览器发生了什么?这个问题看似老生常谈,但是这个问题的回答质量确实能体现面试官知识的广度和深度。本文从浏览器的角度告诉你,输入网址回车后浏览器内部发生了什么,看完本文你就会知道:浏览器中有哪些进程,这些进程的作用是什么浏览器之后地址输入到URL中,内部进程和线程是干什么的?当我们与浏览器进行交互时,内部进程是如何处理这些交互事件的呢?浏览器架构在说浏览器架构之前,我们首先要了解两个概念,进程和线程。进程是程序的一个执行过程,是一个动态的概念,是程序执行过程中分配和管理资源的基本单位。线程是CPU调度和分派的基本单位。其他线程共享进程拥有的所有资源。简单的说,进程可以理解为一个正在执行的应用程序,线程可以理解为我们应用程序中代码的执行者。而他们的关系可想而知,线程运行在进程中,一个进程中可能有一个或多个线程,一个线程只能属于一个进程。大家都知道浏览器属于应用程序,应用程序的执行可以理解为计算机启动一个进程。进程启动后,CPU会为进程分配相应的内存空间。当我们的进程拿到内存后,就可以使用线程进行资源调度,进而完成我们应用程序的功能。在应用程序中,为了满足功能的需要,启动的进程会创建另一个新的进程来处理其他任务。这些新进程拥有新的独立内存空间,不能与原进程向内。如果需要这些进程之间进行通信,可以通过IPC机制(InterProcessCommunication)来完成。很多应用都是采用这种多进程的方式来工作,因为进程之间相互独立,互不影响,也就是说当其中一个进程挂掉时,不会影响其他进程的执行,您只需要重新启动挂起的进程即可恢复运行。浏览器的多进程架构如果我们开发一个浏览器,它的架构可以是单进程多线程应用,也可以是使用IPC通信的多进程应用。不同的浏览器使用不同的架构。下面主要以Chrome为例介绍浏览器的多进程架构。在Chrome中,主要有四个进程:浏览器进程(BrowserProcess):负责浏览器的前进、后退、地址栏、书签栏以及浏览器一些不可见的底层操作,如网络请求、文件访问等。渲染进程(RendererProcess):负责一个Tab中显示相关的工作,也称为渲染引擎。插件进程(PluginProcess):负责控制网页使用的插件GPU进程(GPUProcess):负责处理整个应用的GPU任务这4个进程是什么关系?首先,当我们要浏览网页时,我们会在浏览器的地址栏中输入网址。这时BrowserProcess会向这个URL发送请求,获取这个URL的HTML内容,然后将HTML传递给RendererProcess,RendererProcess解析HTML内容,解析需要请求网络的资源并返回交给BrowserProcess加载,并通知BrowserProcess需要PluginProcess加载插件资源和执行插件代码。解析完成后,RendererProcess计算图像帧并将这些图像帧交付给GPUProcess,GPUProcess将其转换为图像显示屏幕。多进程架构的好处为什么Chrome使用多进程架构?第一,更高的容错性。在当今的WEB应用中,HTML、JavaScript和CSS变得越来越复杂。这些运行在渲染引擎上的代码经常会出现bug,有些bug会直接导致渲染引擎崩溃。多进程架构允许每个渲染引擎在自己的进程中运行,互不影响,也就是说,当其中一个页面崩溃挂掉时,其他页面仍然可以正常运行,不受影响。第二,更高的安全性和沙盒(sanboxing)。渲染引擎在网络上经常会遇到不可信甚至是恶意的代码,他们会利用这些漏洞在你的电脑上安装恶意软件。为了解决这个问题,浏览器针对不同的进程限制了不同的权限,并提供沙盒运行环境,使其更安全可靠。第三,更高的响应速度。在单进程架构下,各个任务相互竞争抢夺CPU资源,拖慢了浏览器的响应速度,而多进程架构正好避免了这个缺点。我们在多进程架构优化之前说过,RendererProcess负责一个Tab中显示相关的工作,也就是说一个Tab都会有一个RendererProcess,这些进程之间的内存是不能共享的。不同进程的内存往往需要包含相同的内容。浏览器的进程模型为了节省内存,Chrome提供了四种进程模型(ProcessModels),不同的进程模型会对tab进程进行不同的处理。Process-per-site-instance(默认)——对同一个站点实例使用一个进程Process-per-site——对同一个站点使用一个进程Process-per-tab——对每个选项卡使用一个进程Singleprocess——使用一个foralltabs这里的流程需要给出site和site-instance的定义。Site指的是相同的注册域名(如:google.com、bbc.co.uk)和scheme(如:https://)。比如a.baidu.com和b.baidu.com可以理解为同一个站点(注意这里要和同源策略区分开来,同源策略还涉及到子域名和端口)。site-instance指的是来自同一个站点的一组相连的页面,其中connected的定义是可以在脚本代码中获取彼此的引用如何理解这段话。如果满足以下两个条件,并且打开的新页面和旧页面属于上面定义的同一个站点,则它们属于同一个站点实例。用户通过这种方式点击的JS代码打开的新页面新页面(如window.open)理解了概念后,下面对四种流程模式进行说明。第一个是单进程。顾名思义,单进程模式,所有选项卡都会使用同一个进程。接下来是Process-per-tab,顾名思义,每打开一个tab,就会创建一个新的进程。对于Process-per-site,当你打开a.baidu.com页面和b.baidu.com页面时,这两个页面的tabs使用相同的process,因为这两个页面的站点是一样的,这样一来,如果其中一个选项卡崩溃,另一个选项卡也会崩溃。Process-per-site-instance是最重要的,因为这是Chrome默认使用的模式,也是几乎所有用户都在使用的模式。当你打开一个tab访问a.baidu.com,再打开一个tab访问b.baidu.com,这两个tab会用到两个进程。而如果在a.baidu.com中通过JS代码打开b.baidu.com页面,这两个tab会使用相同的流程。默认模式选择那么为什么浏览器使用Process-per-site-instance作为默认的进程模式呢?Process-per-site-instance兼顾了性能和易用性,是一种比较通用的模式。与Process-per-tab相比,可以少开很多进程,也就是内存占用少。与Process-per-site相比,可以更好的隔离同域名下不相关的tabs,导航过程更安全发生了什么?前面我们讲了浏览器的多进程架构,多进程架构的各种好处,以及Chrome是如何优化多进程架构的。下面我们从一个用户浏览网页的简单场景来进一步了解这个过程。线程是我们网站页面的呈现方式。在网页加载过程之前,我们提到了除选项卡之外的大部分工作由浏览器进程负责。BrowserProcess根据不同的任务划分不同的工作线程:UI线程:控制浏览器上的按钮和输入框;网络线程:处理网络请求,从互联网上获取数据;存储线程:控制对文件的访问等;第一步:处理输入当我们在浏览器的地址栏输入内容并回车时,UI线程会判断输入的内容是搜索关键字(searchquery)还是URL。如果是搜索关键字,则跳转到搜索URL对应的默认搜索引擎。如果输入内容是一个URL,则开始请求该URL。第二步:开始导航回车后,UI线程会将关键字搜索对应的URL或者输入的URL交给Network线程。此时UI线程会在Tab前面显示图标为loading,然后网络进程会进行DNS寻址、建立TLS连接等一系列操作来请求资源。如果它收到来自服务器的301重定向响应,它会告诉UI线程进行重定向,然后它会再次发起新的网络请求。第三步:读取响应网络线程收到服务器的响应后,开始解析HTTP响应报文,然后根据响应中的Content-Type字段判断响应主体的媒体类型(MIMEType)标头。如果媒体类型是HTML文件,则响应数据将交给渲染器进程进行下一步。如果是zip文件或其他文件,相关数据将传输到下载管理器。同时,浏览器会执行安全浏览安全检查。如果域名或请求内容匹配到已知的恶意站点,网络线程将显示一个警告页面。此外,网络线程还会进行CORB(CrossOriginReadBlocking)检查,确保敏感的跨站数据不会被发送到渲染进程。第四步:找到渲染进程各种检查完成后,网络线程确定浏览器可以导航到请求的网页,网络线程会通知UI线程数据准备好了,UI线程会找到一个渲染器进程渲染网页。为了让浏览器优化查找渲染进程这一步,考虑到网络请求获得响应需要时间,浏览器在第二步就已经提前搜索并启动了一个渲染进程。如果中间步骤一切顺利,当网络线程接收到数据时,渲染进程就准备好了,但是如果发生重定向,准备好的渲染进程可能不可用,此时会重新启动一个渲染进程。第五步:提交导航至此,数据和渲染进程都准备好了,BrowserProcess会向RendererProcess发送一个IPC消息来确认导航。此时浏览器进程会将准备好的数据发送给渲染进程,渲染进程收到数据后,向浏览器进程发送IPC消息,告诉浏览器进程导航已经提交,页面开始加载。这时候导航栏会更新,安全指示器会更新(地址前面的小锁),访问历史列表(历史标签)也会更新,即可以切换页面向前和向后。第六步:初始加载完成。当导航提交完成后,渲染进程开始加载资源并渲染页面(下面会详细介绍)。当页面渲染完成后(页面和内部iframe都触发onload事件),浏览器会向浏览器进程发送IPC消息通知浏览器进程。此时,UI线程将停止在选项卡中显示加载图标。网页渲染原理导航过程完成后,浏览器进程将数据传递给渲染进程,渲染进程负责选项卡中的所有内容。核心目的是将HTML/CSS/JS代码转换成用户可以交互的网页。那么渲染过程是如何工作的呢?在渲染过程中,包含的线程有:一个主线程(mainthread)、多个工作线程(workthread)、一个合成器线程(compositorthread)和多个光栅化线程(rasterthread)。不同的线程有不同的工作职责。构建DOM渲染进程收到导航确认信息后,开始从浏览器进程接收数据。这时,主线程会解析数据并将其转换成DOM(DocumentObjectModel)对象。DOM是一种数据结构和API,供Web开发人员通过JavaScript与网页进行交互。在构建DOM的过程中,资源子加载将解析图像、CSS和JavaScript脚本等资源。这些资源需要从网络或缓存中获取。如果主线程在构建DOM的过程中遇到这些资源,就会一一发起请求。为了获取,并且为了提高效率,浏览器还会运行一个预加载扫描器(preloadscanner)程序,如果HTML中有img、link等标签,预加载扫描器会将这些请求传递给网络线程资源下载的浏览器进程。在下载并执行JavaScript构建DOM的过程中,如果遇到标签中加入async或者defer等属性,浏览器就会异步加载执行JS。不阻塞渲染的代码。Stylecalculation-StylecalculationDOM树就是我们页面的结构。我们需要知道页面是什么样子的,还需要知道DOM每个节点的样式。主线程在解析页面时,如果遇到