- 浏览器创建Document对象并且开始解析web页面,将得到的Element和文本节点添加到document对象中.此时document.readyState值为loading.
- 当HTML解析器遇到不包含async或者defer属性的<script>元素时,将节点添加到document中并且执行该脚本.在这些同步脚本下载和执行期间,解析器将暂停解析.此类同步脚本可以使用document.write()方法向输入流中插入数据.插入的数据在解析器继续工作时将被解析为document中的节点.同步脚本通常只是执行定义函数,注册监听器,他们同样可以遍历并维护document tree,不过这些同步脚本只能看见本身<script>以及前面的元素.
- 当解析器遇到设置了async属性的<script>标签时,它开始下载脚本并且继续解析文档.被下载的文档将在下载完成后尽快运行,整个过程中解析器并不会暂停等待脚本下载.这一类异步脚本不应该使用document.write()方法.异步脚本执行过程中可以访问本身<script>元素以及之前的元素,或者有可能访问再它只会的元素.
- 当解析器遇到设置了defer属性的<script>时,它下载改脚本并继续解析文档,下载的script脚本将在文档解析完成后执行.
- 当文档解析完成只会,document.readyState被设置为interactive.
- 此时设置了defer属性的脚本将按照他们在文档中出现的顺序开始执行.defer脚本可以访问完整的文档树,但是不能使用document.write()方法.
- 所有defer脚本执行完毕只会,浏览器触发document对象的DOMContentLoaded事件.这表明程序从同步脚本执行阶段转换到异步事件驱动阶段.需要注意的是此时任然有可能存在async脚本的执行.
- 此时的文档已经完全解析,但是浏览器任然等待例如图片等资源的加载.当所有内容加载完成并且所有async脚本完成加载并执行完毕,document.readyState属性变为complete并且浏览器出发window对象的load事件.
- 此时事件监听脚本将根据用户输入事件,网络事件等方式触发
当然这是最完美的工作流程,没有一款浏览器完全支持所有细节,其中load事件得到了广泛的支持,所有的浏览器都将触发它,这些事使用最普遍的检测文档完全加载并可用于维护.