浏览器渲染机制及渲染阻塞

渲染机制
浏览器的渲染机制一般分为以下几个步骤

  1. 处理 HTML 并构建 DOM 树。
  2. 处理 CSS 构建 CSSOM 树。
  3. 将 DOM 与 CSSOM 合并成一个渲染树。
  4. 根据渲染树来布局,计算每个节点的位置。
  5. 调用 GPU 绘制,合成图层,显示在屏幕上。

浏览器渲染机制及渲染阻塞_第1张图片
参考1

一个渲染引擎主要包括:HTML解析器,CSS解析器,javascript引擎,布局layout模块,绘图模块

  1. HTML解析器:解释HTML文档的解析器,主要作用是将HTML文本解释成DOM树。
  2. CSS解析器:它的作用是为DOM中的各个元素对象计算出样式信息,为布局提供基础设施
  3. Javascript引擎:使用Javascript代码可以修改网页的内容,也能修改css的信息,javascript引擎能够解释javascript代码,并通过DOM接口和CSS树接口来修改网页内容和样式信息,从而改变渲染的结果。
  4. 布局(layout):在DOM创建之后,Webkit需要将其中的元素对象同样式信息结合起来,计算他们的大小位置等布局信息,形成一个能表达这所有信息的内部表示模型
  5. 绘图模块(paint):使用图形库将布局计算后的各个网页的节点绘制成图像结果

参考2

渲染阻塞

js是解释器阻塞资源;css是渲染阻塞资源

关于CSS加载的阻塞情况:参考3

  1. css加载不会阻塞DOM树的解析
  2. css加载会阻塞DOM树的渲染
  3. css加载会阻塞后面js语句的执行

可以这样顺着流程想,目的都是渲染页面,只是看谁先谁后
所以至少得有dom和css
在没有js的条件下,解析dom,然后css可以并行的构建,最后合并渲染
这个时候,如果有link外链css,会先去外链下载css文件,搞定后再渲染
总之就是css负责的样式,样式的加载,一定是在最终渲染之前的,不然怎么渲染想要的样式

打个比方就是,一个人什么都不穿,本体是dom,css是衣服,link外链css是网购的衣服,渲染就是最后出门
只有dom,裸着,当然可以出门(渲染成功);
有css的时候,dom+css,穿上衣服后,出门;
有外链css的时候,等待网购的衣服到家后在穿上出门;

在有js的条件下,因为js可以操作dom元素,还可以修改style样式
所以理论上来说,js应该是在dom和css都搞定后才入场工作,
css的加载,会阻塞后续的js执行

js能阻塞dom树构建
在html中部,加入js,上下都有btn等dom元素,如果js执行,而页面上没有dom元素
就可以证明js阻塞了dom的构建或者渲染

css能阻塞js执行,link也可以,但是试验不出来,因为就算css出错或者不存在,整个过程是不会中止的,
会继续后面的,不像js出错会报错,
所以通常会把css放在头部,js放在body尾
在渲染该 script标签之下的HTML元素之前,也就是说不等待后续载入的HTML元素,读到就加载并执行。

解析过程中无论遇到的JavaScript是内联还是外链,只要浏览器遇到 script 标记,唤醒 JavaScript解析器,
就会进行暂停 (blocked )浏览器解析HTML,并等到 CSSOM 构建完毕,才去执行js脚本。
因为脚本中可能会操作DOM元素,而如果在加载执行脚本的时候DOM元素并没有被解析,
脚本就会因为DOM元素没有生成取不到响应元素,所以实际工程中,我们常常将资源放到文档底部。

那么问题来了,写在js脚本后面的dom不会解析,但是后面的css或者外链css,会解析吗
下面找到了答案:
无论css阻塞,还是js阻塞,都不会阻塞浏览器加载外部资源(图片、视频、样式、脚本等)
原因:浏览器始终处于一种:“先把请求发出去”的工作模式,只要是涉及到网络请求的内容,
无论是:图片、样式、脚本,都会先发送请求去获取资源,至于资源到本地之后什么时候用,
由浏览器自己协调。这种做法效率很高。
所以,css外链写在后面的话,可以加载,但也不一定,要看网络速度,但是css写着后面就暂时不会解析
外链js,会先下载,前面的代码不会阻塞下载过程,等运行到了该行代码的位置了,就按照之前的规则来

每一次script后都会渲染之前解析完的dom,但后续的不会
所以可以理解是页面的渲染不一定是一次就完成的,比如下方的代码
在alert(‘本身’)后,页面会出现btn2,但是不会出现js脚本后面的btn2,
这个时候已经渲染完了一次,等btn1解析完等待渲染的时候,出现了alert(‘3’)的js代码
所以等alert3后才会显示btn1

    <link rel="stylesheet" href="inde.css">
    <button id="2">2</button>
    <script>
        alert('本身')
    </script>
    <script src="1.js"></script>//里面是alert('test')
    <button id="1">1</button>
    <script>
        alert(3)
    </script>

浏览器渲染机制及渲染阻塞_第2张图片
浏览器渲染机制及渲染阻塞_第3张图片
浏览器渲染机制及渲染阻塞_第4张图片
浏览器渲染机制及渲染阻塞_第5张图片

总结来说:

  • 无论css阻塞,还是js阻塞,都不会阻塞浏览器加载外部资源(图片、视频、样式、脚本等)
    所以css外链,js外链,如果不是网络原因,在html往下解析的过程中都可以视为已经下载好,变成内部的了

  • css不会阻塞渲染(可能会产生“闪屏现象”);

  • css外链link形式可能因为网络慢的关系加载慢而阻塞渲染

  • css会阻塞其后的js执行;

  • js不管是js脚本还是script src外链,只要浏览器遇到 script 标记,唤醒 JavaScript解析器,就会进行暂停
    (blocked )浏览器解析HTML,并等到 CSSOM构建完毕(对应了上一条,css会阻塞js),才去执行js脚本。因为脚本中可能会操作DOM元素,而如果在加载执行脚本的时候DOM元素并没有被解析,脚本就会因为DOM元素没有生成取不到响应元素,所以常常将资源放到文档底部。

  • script标签的js每次执行完后都会渲染前面代码已经解析完的dom,这是宏任务相关的点(在浏览器中,在下一个macrotask执行开始前,浏览器可以进行页面渲染)。上述例子中可以看到,就算整个html后面还有其他的dom元素未被渲染,用alert能看出,只渲染了前半部分的dom,点击确定alert后,后续的dom就继续渲染了。涉及到宏任务参考本人后面写的一篇文章链接。

你可能感兴趣的:(总结帖,面试,javascript,html5,css)