当你在浏览器地址栏输入一个地址时会发生什么时(超详细版)

346 阅读15分钟

当你在地址栏输入地址时,浏览器进程的ui线程会捕捉到你的输入内容,如果访问的是网站,则ui线程会启动一个网络线程来请求dns进行域名解析,开始连接服务器获取数据(期间会经历tcp的三次握手)如果你的输入不是网址而是一窜关键词,浏览器就会知道你是要搜索,于是会调用你默认设置的搜索引擎进行关键字搜索

当网络线程获取到你的数据后,会通过SafeBrowsing(SafeBrowsing谷歌内部站点安全系统,比如通过检测站点数据来判断是否安全,比如通过该站点的ip是否在谷歌的黑名单之内来判断安全性)里检测站点是不是一个安全的站点,如果有问题,浏览器会阻止你访问并给你提示,当然你也可以选择不理会继续访问。

当返回的数据准备好了并通过了安全检验后,网络线程就会通知ui线程我准备好了,然后ui线程会创建一个渲染器进程(Render Thread)来渲染页面,浏览器进程通过IPC管道将数据传递给渲染器进程,正式进入渲染流程。

渲染器进程接到的数据也就是html,渲染器进程的核心任务就是吧html,js,css,image等资源渲染成用户可以交互的web页面,渲染器进程的主线程将html进行解析,构造dom数据结构; html先经过tokeniser标记化,通过词法分析将输入的html内容解析成多个标记,根据识别后的标记进行dom树构造,在dom树构造过程中会创建document对象,然后以document为根节点的dom树不断进行修改向其中添加各种元素,html代码中往往会引入一些额外的资源,比如图片,css,js,等 图片和css等资源需要通过网络下载或从缓存中直接加载,这些资源不会阻塞html的解析,因为他们不会影响dom的生成,但当htm解析过程中遇到了script标签就会停止html解析流程,转去加载并解析执行js,因为浏览器并不知道js执行是否会改变dom的结构,所以要先执行完js在解析dom(例如js里如果调用了document.write那html结构就被破坏了,那之前解析的就没意义了) 也就是说为什么我们一直说要把scrpt标签放在合适的位置,或者使用async或defer来异步加载执行js。

html解析后我们会得到一个dom tree 但我们还不知道dom树上的每个节点应该长什么样子。主线程需要解析css并确定每个dom节点的计算样式,即使没指定样式浏览器默认也会有自己的css样式。 在知道dom结构和每个节点的样式后,就需要知道每个节点放在页面上的哪个位置,也就是节点的坐标和该节点占用的区域,这个阶段就是layout布局。主线程通过遍历dom和计算好的样式来生成layout tree,layout tree上的每个节点都记录了x,y坐标和边框尺寸。这里需要注意的一点的dom tree和layout tree并不是一一对应的,设置了display:none的节点不会出现在layout tree上,而在伪类添加的content值的元素,content值的内容会出现在layout tree上而不会出现在dom tree上,这是因为dom是通过html解析获得, 并不关系样式,而layout tree是根据dom tree和计算好的样式来生成的 。 layout tree是和最后展示在屏幕上的节点是对应的。

知道了元素的形状大小形状和位置后我们还需要知道以什么样的顺序来绘制这个节点,比如z-index属性会影响层级关系。为了保证在屏幕上显示正确的层级,主线程遍历layout tree创建一个绘制记录表(pain record),该表会记录绘制的顺序,这个阶段会被称为绘制(paint)。

知道了绘制的信息,就需要把这些信息点转成成像素点显示在屏幕上了,这个行为就被是栅格化(Restering)。 现在的chrome使用的栅格化叫做合成(composting),合成是一种将页面的各个部分分成多个图层,分别对其进行栅格化,并在合成器的线程中单独进行合成页面的技术,简单来说就是页面所有的元素按照某种规则进行分图层,并把图层都栅格化好了,然后只需要把可视区的内容组合成一帧展示给用户即可。

主线程遍历layout tree生成了layer tree,当layer tree生成完毕和绘制顺序确定后,主线程将这些信息传递给合成器线程,合成器将每个图层栅格化。由于一层可能像页面的整个长度一样大,因此合成器线程将他们切分为许多图块,再把每个图块发送给栅格化线程,栅格线程栅格化每个图块,并将他们存储在GPU内存中,当图块栅格化完成后,合成器线程将手机称为”draw quads“的图块信息,这些信息记录了图块在内存中的位置和在页面的哪个位置绘制图块的信息,根据这些信息合成器线程生成了一个合成器帧,然后这个合成器帧通过IPC传送给了浏览器进程,浏览器进程将合成器帧传送到GPU,然后GPU渲染展示到屏幕上,这时候就看到了页面的内容。当你滚动了页面,都会生成一个新的合成器帧,新的帧再传给GPU再次渲染到屏幕上 当网络线程获取到你的数据后,会通过SafeBrowsing(SafeBrowsing谷歌内部站点安全系统,比如通过检测站点数据来判断是否安全,比如通过该站点的ip是否在谷歌的黑名单之内来判断安全性)里检测站点是不是一个安全的站点,如果有问题,浏览器会阻止你访问并给你提示,当然你也可以选择不理会继续访问。

当返回的数据准备好了并通过了安全检验后,网络线程就会通知ui线程我准备好了,然后ui线程会创建一个渲染器进程(Render Thread)来渲染页面,浏览器进程通过IPC管道将数据传递给渲染器进程,正式进入渲染流程。

渲染器进程接到的数据也就是html,渲染器进程的核心任务就是吧html,js,css,image等资源渲染成用户可以交互的web页面,渲染器进程的主线程将html进行解析,构造dom数据结构; html先经过tokeniser标记化,通过词法分析将输入的html内容解析成多个标记,根据识别后的标记进行dom树构造,在dom树构造过程中会创建document对象,然后以document为根节点的dom树不断进行修改向其中添加各种元素,html代码中往往会引入一些额外的资源,比如图片,css,js,等 图片和css等资源需要通过网络下载或从缓存中直接加载,这些资源不会阻塞html的解析,因为他们不会影响dom的生成,但当htm解析过程中遇到了script标签就会停止html解析流程,转去加载并解析执行js,因为浏览器并不知道js执行是否会改变dom的结构,所以要先执行完js在解析dom(例如js里如果调用了document.write那html结构就被破坏了,那之前解析的就没意义了) 也就是说为什么我们一直说要把scrpt标签放在合适的位置,或者使用async或defer来异步加载执行js。

html解析后我们会得到一个dom tree 但我们还不知道dom树上的每个节点应该长什么样子。主线程需要解析css并确定每个dom节点的计算样式,即使没指定样式浏览器默认也会有自己的css样式。 在知道dom结构和每个节点的样式后,就需要知道每个节点放在页面上的哪个位置,也就是节点的坐标和该节点占用的区域,这个阶段就是layout布局。主线程通过遍历dom和计算好的样式来生成layout tree,layout tree上的每个节点都记录了x,y坐标和边框尺寸。这里需要注意的一点的dom tree和layout tree并不是一一对应的,设置了display:none的节点不会出现在layout tree上,而在伪类添加的content值的元素,content值的内容会出现在layout tree上而不会出现在dom tree上,这是因为dom是通过html解析获得, 并不关系样式,而layout tree是根据dom tree和计算好的样式来生成的 。 layout tree是和最后展示在屏幕上的节点是对应的。

知道了元素的形状大小形状和位置后我们还需要知道以什么样的顺序来绘制这个节点,比如z-index属性会影响层级关系。为了保证在屏幕上显示正确的层级,主线程遍历layout tree创建一个绘制记录表(pain record),该表会记录绘制的顺序,这个阶段会被称为绘制(paint)。

知道了绘制的信息,就需要把这些信息点转成成像素点显示在屏幕上了,这个行为就被是栅格化(Restering)。 现在的chrome使用的栅格化叫做合成(composting),合成是一种将页面的各个部分分成多个图层,分别对其进行栅格化,并在合成器的线程中单独进行合成页面的技术,简单来说就是页面所有的元素按照某种规则进行分图层,并把图层都栅格化好了,然后只需要把可视区的内容组合成一帧展示给用户即可。

主线程遍历layout tree生成了layer tree,当layer tree生成完毕和绘制顺序确定后,主线程将这些信息传递给合成器线程,合成器将每个图层栅格化。由于一层可能像页面的整个长度一样大,因此合成器线程将他们切分为许多图块,再把每个图块发送给栅格化线程,栅格线程栅格化每个图块,并将他们存储在GPU内存中,当图块栅格化完成后,合成器线程将手机称为”draw quads“的图块信息,这些信息记录了图块在内存中的位置和在页面的哪个位置绘制图块的信息,根据这些信息合成器线程生成了一个合成器帧,然后这个合成器帧通过IPC传送给了浏览器进程,浏览器进程将合成器帧传送到GPU,然后GPU渲染展示到屏幕上,这时候就看到了页面的内容。当你滚动了页面,都会生成一个新的合成器帧,新的帧再传给GPU再次渲染到屏幕上

当网络线程获取到你的数据后,会通过SafeBrowsing(SafeBrowsing谷歌内部站点安全系统,比如通过检测站点数据来判断是否安全,比如通过该站点的ip是否在谷歌的黑名单之内来判断安全性)里检测站点是不是一个安全的站点,如果有问题,浏览器会阻止你访问并给你提示,当然你也可以选择不理会继续访问。

当返回的数据准备好了并通过了安全检验后,网络线程就会通知ui线程我准备好了,然后ui线程会创建一个渲染器进程(Render Thread)来渲染页面,浏览器进程通过IPC管道将数据传递给渲染器进程,正式进入渲染流程。

渲染器进程接到的数据也就是html,渲染器进程的核心任务就是吧html,js,css,image等资源渲染成用户可以交互的web页面,渲染器进程的主线程将html进行解析,构造dom数据结构; html先经过tokeniser标记化,通过词法分析将输入的html内容解析成多个标记,根据识别后的标记进行dom树构造,在dom树构造过程中会创建document对象,然后以document为根节点的dom树不断进行修改向其中添加各种元素,html代码中往往会引入一些额外的资源,比如图片,css,js,等 图片和css等资源需要通过网络下载或从缓存中直接加载,这些资源不会阻塞html的解析,因为他们不会影响dom的生成,但当htm解析过程中遇到了script标签就会停止html解析流程,转去加载并解析执行js,因为浏览器并不知道js执行是否会改变dom的结构,所以要先执行完js在解析dom(例如js里如果调用了document.write那html结构就被破坏了,那之前解析的就没意义了) 也就是说为什么我们一直说要把scrpt标签放在合适的位置,或者使用async或defer来异步加载执行js。

html解析后我们会得到一个dom tree 但我们还不知道dom树上的每个节点应该长什么样子。主线程需要解析css并确定每个dom节点的计算样式,即使没指定样式浏览器默认也会有自己的css样式。 在知道dom结构和每个节点的样式后,就需要知道每个节点放在页面上的哪个位置,也就是节点的坐标和该节点占用的区域,这个阶段就是layout布局。主线程通过遍历dom和计算好的样式来生成layout tree,layout tree上的每个节点都记录了x,y坐标和边框尺寸。这里需要注意的一点的dom tree和layout tree并不是一一对应的,设置了display:none的节点不会出现在layout tree上,而在伪类添加的content值的元素,content值的内容会出现在layout tree上而不会出现在dom tree上,这是因为dom是通过html解析获得, 并不关系样式,而layout tree是根据dom tree和计算好的样式来生成的 。 layout tree是和最后展示在屏幕上的节点是对应的。

知道了元素的形状大小形状和位置后我们还需要知道以什么样的顺序来绘制这个节点,比如z-index属性会影响层级关系。为了保证在屏幕上显示正确的层级,主线程遍历layout tree创建一个绘制记录表(pain record),该表会记录绘制的顺序,这个阶段会被称为绘制(paint)。

知道了绘制的信息,就需要把这些信息点转成成像素点显示在屏幕上了,这个行为就被是栅格化(Restering)。 现在的chrome使用的栅格化叫做合成(composting),合成是一种将页面的各个部分分成多个图层,分别对其进行栅格化,并在合成器的线程中单独进行合成页面的技术,简单来说就是页面所有的元素按照某种规则进行分图层,并把图层都栅格化好了,然后只需要把可视区的内容组合成一帧展示给用户即可。

主线程遍历layout tree生成了layer tree,当layer tree生成完毕和绘制顺序确定后,主线程将这些信息传递给合成器线程,合成器将每个图层栅格化。由于一层可能像页面的整个长度一样大,因此合成器线程将他们切分为许多图块,再把每个图块发送给栅格化线程,栅格线程栅格化每个图块,并将他们存储在GPU内存中,当图块栅格化完成后,合成器线程将手机称为”draw quads“的图块信息,这些信息记录了图块在内存中的位置和在页面的哪个位置绘制图块的信息,根据这些信息合成器线程生成了一个合成器帧,然后这个合成器帧通过IPC传送给了浏览器进程,浏览器进程将合成器帧传送到GPU,然后GPU渲染展示到屏幕上,这时候就看到了页面的内容。当你滚动了页面,都会生成一个新的合成器帧,新的帧再传给GPU再次渲染到屏幕上