Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

浏览器、页面 #22

Open
AngusLius opened this issue Jul 28, 2018 · 0 comments
Open

浏览器、页面 #22

AngusLius opened this issue Jul 28, 2018 · 0 comments

Comments

@AngusLius
Copy link
Owner

AngusLius commented Jul 28, 2018

重排、重绘

当 DOM 元素的属性发生变化 (如 color) 时, 浏览器会通知 render 重新描绘相应的元素, 此过程称为 repaint。

如果该次变化涉及元素布局 (如 width), 浏览器则抛弃原有属性, 重新计算并把结果传递给 render 以重新描绘页面元素, 此过程称为 reflow。

下列情况会发生重排:

  • 添加、删除、更新DOM节点
  • 通过display: none隐藏一个DOM节点-触发重排和重绘
  • 通过visibility: hidden隐藏一个DOM节点-只触发重绘,因为没有几何变化
  • 移动或者给页面中的DOM节点添加动画
  • 添加一个样式表,调整样式属性
  • 用户行为,例如调整窗口大小,改变字号,或者滚动。

如何减少重排、重绘

1、不要逐个变样式
2、通过documentFragment来保留临时变动
3、通过display:none属性隐藏元素(只有一次重排重绘),添加足够多的变更后,通过display属性显示(另一次重排重绘)。通过这种方式即使大量变更也只触发两次重排。
4、不要频繁计算样式。如果你有一个样式需要计算,只取一次,将它缓存在一个变量中并且在这个变量上工作。

浏览器渲染机制

DOM解析和渲染

1.js放在head中会立即执行,阻塞后续的资源下载与执行。因为js有可能会修改dom,如果不阻塞后续的资源下载,dom的操作顺序不可控。

  正常的网页加载流程是这样的。

浏览器一边下载HTML网页,一边开始解析
解析过程中,发现<script>标签
暂停解析,网页渲染的控制权转交给JavaScript引擎
如果<script>标签引用了外部脚本,就下载该脚本,否则就直接执行
执行完毕,控制权交还渲染引擎,恢复往下解析HTML网页
  如果外部脚本加载时间很长(比如一直无法完成下载),就会造成网页长时间失去响应,浏览器就会呈现“假死”状态,这被称为“阻塞效应”。html需要等head中所有的js和css加载完成后才会开始绘制,但是html不需要等待放在body最后的js下载执行就会开始绘制,因此将js放在body的最后面,可以避免资源阻塞,同时使静态的html页面迅速显示。将脚本文件都放在网页尾部加载,还有一个好处。在DOM结构生成之前就调用DOM,JavaScript会报错,如果脚本都在网页尾部加载,就不存在这个问题,因为这时DOM肯定已经生成了。

CSS

GUI渲染线程与JS引擎是互斥的
1、CSS 不会阻塞 DOM 的解析

<link rel="stylesheet" href="/css/sleep3000-common.css">

浏览器是解析DOM生成DOM Tree,结合CSS生成的CSS Tree,最终组成render tree,再渲染页面。由此可见,在此过程中CSS完全无法影响DOM Tree,因而无需阻塞DOM解析。
2、CSS 阻塞页面渲染

JS

JS 阻塞 DOM 解析,但浏览器会"偷看"DOM,预先下载相关资源。

<script>

浏览器遇到 <script>且没有defer或async属性的标签时,会触发页面渲染,因而如果前面CSS资源尚未加载完毕时,浏览器会等待它加载完毕再执行脚本。

其实浏览器都有一个超时时间,如果超时没有返回,那么会加载失败,浏览器就会放弃加载这个js,直接跳过了,如果之后的js依赖这个文件,那么就有可能会出问题了。

X机制在并行加载资源时,保证JS执行顺序和书写顺序/依赖顺序一致,尽管它们的加载顺序不是一致的。

参考链接

https://juejin.im/post/59c60691518825396f4f71a1

页面生命周期

DOMContentLoaded

事件触发时,仅当html完全加载,DOM树构建完成,不包括样式表,图片,flash。

document.addEventListener("DOMContentLoaded", ready);

此时,获取图片大小为0

  // image is not yet loaded (unless was cached), so the size is 0x0
    alert(`Image size: ${img.offsetWidth}x${img.offsetHeight}`);

用于:
DOM加载完毕,所以js可以访问所有DOM节点,初始化界面。

asyc、defer

带有async和defer的脚本的下载是和HTML的下载与解析是异步的,但是js的执行一定是和UI线程是互斥的

68747470733a2f2f757365722d676f6c642d63646e2e786974752e696f2f323031372f31302f32382f3165366337383634646233316137633430306436303063376332393433303462

1、async

2、defer
通知浏览器该脚本将在文档完成解析后,触发 DOMContentLoaded 事件前执行。

浏览器自动补全

例如,如果页面有登录的界面,浏览器记住了该页面的用户名和密码,那么在 DOMContentLoaded运行的时候浏览器会试图自动补全表单(如果用户设置允许)。

window.onload

所有的DOM,样式表,脚本,图片,flash都已经加载完成了。

<script>
  window.onload = function() {
    alert('Page loaded');
    // image is loaded at this time
    alert(`Image size: ${img.offsetWidth}x${img.offsetHeight}`);
  };
</script>
<img id="img" src="https://en.js.cx/clipart/train.gif?speed=1&cache=0">
// 一个典型的offsetWidth是测量包含元素的边框(border)、水平线上的内边距(padding)、竖直方向滚动条(scrollbar)(如果存在的话)、以及CSS设置的宽度(width)的值。

用于:
附加资源已经加载完毕,可以在此事件触发时获得图像的大小。

beforeunload

当浏览器窗口,文档或其资源将要卸载时,会触发beforeunload事件。这个文档是依然可见的,并且这个事件在这一刻是可以取消的。
用于:
用户正在离开页面:可以询问用户是否保存了更改以及是否确定要离开页面。

unload

当文档或者一个子资源将要被卸载时,在beforeunload 、pagehide两个事件之后触发。
文档会处于一个特定状态。

  • 所有资源仍存在 (图片, iframe 等.)
  • 对于终端用户所有资源均不可见
  • 界面交互无效 (window.open, alert, confirm 等.)
  • 错误不会停止卸载文档的过程

readyState、readystatechange

document.readyState属性给了我们加载的信息,有三个可能的值:

  • loading 加载 - document仍在加载。
  • interactive 互动 - 文档已经完成加载,文档已被解析,但是诸如图像,样式表和框架之类的子资源仍在加载。
  • complete - 文档和所有子资源已完成加载。状态表示 load 事件即将被触发。

每当文档的加载状态改变的时候就有一个readystatechange事件被触发,所以我们可以打印所有的状态

// current state
console.log(document.readyState);

// print state changes
document.addEventListener('readystatechange', () => console.log(document.readyState));

readystatechange的在各个事件中的执行顺序又是如何呢

<script>
  function log(text) { /* output the time and message */ }
  log('initial readyState:' + document.readyState);

  document.addEventListener('readystatechange', () => log('readyState:' + document.readyState));
  document.addEventListener('DOMContentLoaded', () => log('DOMContentLoaded'));

  window.onload = () => log('window onload');
</script>

<iframe src="iframe.html" onload="log('iframe onload')"></iframe>

<img src="http://en.js.cx/clipart/train.gif" id="img">
<script>
  img.onload = () => log('img onload');
</script>

输出如下:
[1] initial readyState:loading
[2] readyState:interactive
[2] DOMContentLoaded
[3] iframe onload
[4] readyState:complete
[4] img onload
[4] window onload

jquery类库中$(document).ready()

ready对应的状态是初始化dom已经加载完成。
readystatechange中的complete、interactive 还有一个DOMContentLoaded也是初始dom加载完成,作为判断条件

参考链接

页面的生命周期:fi3ework/blog#3

@AngusLius AngusLius changed the title html 浏览器、页面 Jul 29, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant