# 页面生命周期

页面中的生命周期主要有三个

*   **DOMContentLoaded**

    这个是dom树构建完成之后，并没有进行加载资源(styles, imgs).处理cssom之前的dom树完成的情况.[html.js.css渲染顺序.md](https://github.com/xiaohesong/TIL/blob/master/front-end/html.js.css%E6%B8%B2%E6%9F%93%E9%A1%BA%E5%BA%8F.md)

    *   **DOMContentLoaded and scripts**

        我们知道js加载会阻塞dom树的构建，因此可知道dom树构建完成的时候，js是已经解析完成了(正常情况)

        非正常的情况，就是js脚本的加载方式(async, defer)

        > ⚠️`async`和`defer`这两个属性仅仅适用于外部属性，即脚本指定了`src`属性，否则会被忽略。

        使用这两个属性，浏览器就知道会去继续解析dom,并且在后台加载执行这些js。

        `script`的这两个属性(async, defer)还是有些不同的.

        *   async

            加载顺序: 谁先加载谁就先执行。

            DOMContentLoaded: 在dom未完全解析之前，在这个阶段就可以下载执行异步的脚本。如果脚本很小或缓存，并且文档足够长，就会发生这种情况
        *   defer

            加载顺序： defer的这个属性，始终是按照在dom中的顺序来加载执行。

            DOMContentLoaded： 他会延迟到在dom加载解析之后加载执行，但是在DOMContentLoaded事件之前。
    *   **DOMContentLoaded and styles**

        我们知道，css不会直接的阻塞dom树的构建，但是css的解析执行会阻塞js的下载执行，从而间接的影响到dom的构建.
    *   **Built-in browser autofill**

        浏览器内置的填充功能，比如有些网站的登录的账号密码，会在DOMContentLoaded时自动填充进去，用户允许的情况。

        因此脚本长时间加载执行，会导致DOMContentLoaded在等待，填充的功能也在等待。所以`async`和`defer`也可以防止这一点。
*   **load**

    浏览器加载了所有资源之后。
*   **beforeunload/unload**

    用户离开页面时候触发。

    unload和beforeunload的区别是，一个是已经卸载了，一个是在卸载之前。所以如果有一些确定的东西，大多在`beforeunload`中处理。
*   **document.readyState**

    有些时候需要知道页面执行到了哪个阶段，去执行相应的脚本。就可以通过readyState来知晓。readyState有三个阶段：

    1. loading => dom加载中
    2. interactive => dom解析完成,几乎与DOMContentLoaded同时发生，但是在DOMContentLoaded之前
    3. complete => 全部资源加载完毕，window.load.

    `readyState`有个对应的`readystatechange`事件，每次`readyState`变化的时候，都会调用`readystatechange`
