web浏览器渲染流程,window.onload() 与 $(window).load()、$(document).ready() 与 $(function(){}) 的区别和关联

 

一、前言

   我们在编写前端代码的js文件时,往往是会先写一个$(function(){}),然后才会在大括号里面继续写我们自己的代码。当时并不能理解为什么要添加这样一个东西,只是把它当做一个标签一样添加到代码中。直到有一次单独写个页面,把它给漏掉了,于是。。。

  报错了,UNcaught ReferenceError: ... is not defined

  原来$(function(){})的作用是将括号中的代码,延迟到HTML的DOM树构建完成再执行,这样就可以避免:js操作先于DOM树创建而引起的bug。

  可是刚刚理解了这个$(function(){}),window.onload = function(){}又出现了,这又是个什么东东。。。好像和前者一样的作用,可是又有区别,笔者表示困惑了。

 

 

 二、window.onload() 与 $(window).load()、$(document).ready() 与 $(function(){}) 的区别和关联性

1. 关联

  • $(window).load() 类似于 window.onload() ,$(window).load() 实际是 window.addEventListener("load", function (e) {}, false)
  • $(function(){}) 是 $(document).ready() 的简写

2. 执行时机

  • window.onload(),即$(window).load()  是在页面内容完全加载完成执行(包括图片文件等)
  • $(function(){}),即 $(document).ready() 是在DOM结构树绘制完成时执行,无需等待文件加载

3. 使用限制

  • window.onload(),一个项目中只能执行一次,若有多个,后者覆盖前者,注意$(window).load()  不是
  • $(function(){}),即 $(document).ready()  可以使用多个

 

测试:

<script>
    $(window).load(function() {
        console.log("$(window).load()" + 123)
    })
    $(window).load(function() {
        console.log("$(window).load()" + 456)
    })

    window.onload = function() {
        console.log("window.onload = " + 111)
    }
    window.onload = function() {
        console.log("window.onload = " + 222)
    }

    window.onload(function() {
        console.log("window.onload()" + 333)
    }) 
    window.onload(function() {
        console.log("window.onload()" + 444)
    })

    $(function(){
        console.log("$(function(){})" + 555)
    })
    $(function(){
        console.log("$(function(){})" + 666)
    })

    $(document).ready(function(){
        console.log("$(document).ready()" + 777)
    }) 
    $(document).ready(function(){
        console.log("$(document).ready()" + 888)
    }) 
</script>

结果:

 

 由此可见, 执行顺序是:

window.onload *2 —— $(function(){}) —— $(document).ready() —— $(window).load() —— window.onload *1

其中,可得结论: 

  • $(function(){}) 与 $(document).ready()  应该是摆放顺序的问题
  • window.onload(function() {}) 这是错误写法,不执行
  • window.onload 如果有多个,只执行后一个

疑惑:

  • window.onload为啥先执行两遍,最后的最后又执行一遍,这和之前了解的只在完全加载完成时执行,不大符合。(会不会是写了两遍的原因,试试。。。)

 

再试一遍:

<script>
    $(window).load(function() {
        console.log("$(window).load()" + 123)
    })
    $(window).load(function() {
        console.log("$(window).load()" + 456)
    })

    window.onload = function() {
        console.log("window.onload = " + 111)
    }
    // window.onload = function() {
    //     console.log("window.onload = " + 222)
    // }

    window.onload(function() {
        console.log("window.onload()" + 333)
    }) 
    window.onload(function() {
        console.log("window.onload()" + 444)
    })

    $(document).ready(function(){
        console.log("$(document).ready()" + 777)
    }) 
    $(document).ready(function(){
        console.log("$(document).ready()" + 888)
    }) 
    
    $(function(){
        console.log("$(function(){})" + 555)
    })
    $(function(){
        console.log("$(function(){})" + 666)
    })
</script>

 结论:

  • $(function(){}) 与 $(document).ready()  确实是摆放顺序的问题
  • window.onload 还是执行两遍,最后又执行了一遍(不是因为写了两遍)

 

最终结论:

执行顺序: window.onload *2 —— $(function(){}) 或 $(document).ready() —— $(window).load() —— window.onload *1

window.onload的使用: window.onload 只能用一次,否则后者覆盖前者(但是和它类似的$(window).load() 可以执行多个)

 

结合上文提到的:

$(function(){}) 与 $(document).ready()  是DOM结构绘制完毕后就执行,不必等到加载完毕。 即:DOM树加载完毕就执行,不必等到页面中图片或其他外部文件都加载完毕。并且可以写多个。

 

另外引用:


window.onload = function (e) {}//这种方式只能对同一事件绑定一个函数

window.addEventListener("load", function (e) {}, false)//这种方式可以对同一事件绑定多个函数,jquery绑定事件的内部也是调用的 addEventListener

 

 $(window).load()  window.onload 的区别:

window.onload只能用一次,否则后者覆盖前者, $(window).load() 实际是 window.addEventListener("load", function (e) {}, false),可以使用多次

 

 

三、浏览器渲染流程

通过网络模块加载到HTML文件后渲染引擎渲染流程如下,这也通常被称作关键渲染路径(Critical Rendering Path):

  1. 解析html以构建dom树(构建DOM节点):渲染引擎开始解析html,并将标签转化为内容树中的dom节点。

  2. 构建render树(解析样式信息):解析外部CSS文件及style标签中的样式信息。Render树由一些包含有各种属性的矩形组成,它们将被按照正确的顺序显示到屏幕上。

  3. 布局render树(布局DOM节点):执行布局过程,它将确定每个节点在屏幕上的确切坐标。

  4. 绘制render树(绘制DOM节点):Render树构建好了之后,将会再下一步就是绘制,即遍历render树,并使用UI后端层绘制每个节点。

以上就是HTML渲染的基本流程,但这并不包含解析过程中浏览器加载外部资源如图片、脚本、iframe等的过程。

说白了,上面的四步仅仅是HTML结构的渲染流程,而外部资源的加载在HTML结构的渲染流程中贯穿始终,即便绘制DOM节点已经完成,外部资源依然可能正在加载中或尚未加载。

 

 对于HTML浏览器有专门的html解析器来解析,并在解析的过程中构建DOM树。在这里我们讨论两种DOM元素的解析,即样式(link、style)与脚本文件(script)。由于浏览器采用自上而下的方式解析,在遇到这两种元素时都会阻塞浏览器的解析,直到外部资源加载并解析或执行完毕后才会继续向下解析html。

 

1)外部样式会阻塞后续脚本执行,直到外部样式加载并解析完毕。

2)外部样式不会阻塞后续外部脚本的加载,但会阻塞外部脚本的执行。

3)如果后续外部脚本含有async属性(IE下为defer),则外部样式不会阻塞该脚本的加载与执行

4)对于动态创建的link标签不会阻塞其后动态创建的script的加载与执行,不管script标签是否具有async属性,但对于其他非动态创建的script,以上三条结论仍适用

动态创建的外部脚本并未受link的阻塞。

 

posted @ 2018-06-15 18:10  南歌子  阅读(1664)  评论(0编辑  收藏  举报