文章目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>

</head>
<body>
<div id="links" onmouseover = "change()">svdr</div>

</body>
<script>
window.onload = function() {

}
function change(){
alert('ok');
}
</script>

</html>

这种情况下代码正常运行
程序正常运行
,但当把change()函数放在window.onload()里加载时会报错,即:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>

</head>
<body>
<div id="links" onmouseover = "change()">svdr</div>

</body>
<script>
/*
window.onload = function() {
var aLink = document.getElementById('links');
var bLink = aLink;
}
function change(){
alert('ok');
}
*/


window.onload = function() {

function change(){
alert('ok');
}
}

</script>

</html>

报错

当时在编写的过程中出现这种问题也是觉得不可思议的,后面就去了解了window.onload的加载过程与渲染html的顺序,才知道出现这种问题的原因:
一、window.onload的详解
window.onload 是页面全部加载完成,甚至包括图片,而我们实际上经常需要的是文档 DOM 加载完毕!
1、浏览器的工作流程:
这里写图片描述
从上面这个图中,我们可以知道:

1)浏览器会解析三个东西:

一个是HTML/SVG/XHTML,事实上,Webkit有三个C++的类对应这三类文档。解析这三种文件会产生一个DOM Tree。
CSS,解析CSS会产生CSS规则树。
Javascript,脚本,主要是通过DOM API和CSSOM API来操作DOM Tree和CSS Rule Tree.
2)解析完成后,浏览器引擎会通过DOM Tree 和 CSS Rule Tree 来构造 Rendering Tree。注意:

Rendering Tree 渲染树并不等同于DOM树,因为一些像Header或display:none的东西就没必要放在渲染树中了。
CSS 的 Rule Tree主要是为了完成匹配并把CSS Rule附加上Rendering Tree上的每个Element。也就是DOM结点。也就是所谓的Frame。
然后,计算每个Frame(也就是每个Element)的位置,这又叫layout和reflow过程。
3)最后通过调用操作系统Native GUI的API绘制。

2、浏览器加载和渲染html的顺序
(1)IE下载的顺序是从上到下,渲染html的顺序也是从上到下,下载和渲染是同时进行的。
(2)在渲染到页面的某一部分时,其上面的所有部分都已经下载完成(并不是说所有相关联的元素都已经下载完)
(3)如果遇到语义解释性的标签嵌入文件(JS脚本,CSS样式),那么此时IE的下载过程会启用单独连接进行下载。
(4)并且在下载后进行解析,解析过程中,停止页面所有往下元素的下载。阻塞加载
(5)样式表在下载完成后,将和以前下载的所有样式表一起进行解析,解析完成后,将对此前所有元素(含以前已经渲染的)重新进行渲染。
(6)JS、CSS中如有重定义,后定义函数将覆盖前定义函数

  1. JS的加载
    (1) 不能并行下载和解析(阻塞下载)
    (2)当引用了JS的时候,浏览器发送1个js request就会一直等待该request的返回。因为浏览器需要1个稳定的DOM树结构,而JS中很有可能有代码直接改变了DOM树结构,比如使用 document.write 或 appendChild,甚至是直接使用的location.href进行跳转,浏览器为了防止出现JS修改DOM树,需要重新构建DOM树的情况,所以 就会阻塞其他的下载和呈现.

因此,window.onload 是页面全部加载完成,甚至包括图片,而我们实际上经常需要的是文档 DOM 加载完毕;往往就是在我们没有彻底弄清楚它们之间的顺序而导致的一些不理解的编程错误。
其次,HTML加载时由上往下的,在HTML加载的时候,遇到function关键字,声明一个函数的时候,就会在内存中开辟一个新的空间来对函数进行存储,方便以后进行调用。
所以,当将function f()写到window.onload()=function(){}内部的时候,需要整个页面加载完成的之后,才声明这个函数,也就意味着,当HTML加载到onclick=”f()”的时候,window.onload=function(){}里面的函数f还没有被声明,这时候内存中就找不到function f(),于是就会报错。
那么,将function f()移到window.onload()=function(){}外,则HTML加载到的时候就会声明函数f了,所以进行onclick绑定的时候就能够在内存中找到f()并进行调用。
除了这是涉及HTML加载顺序的问题,还有一点就是可以从函数作用域这方面去考虑。写在window.onload()=function(){}内部的function f()就是在一个匿名函数内部的局部函数,并不是全局函数,所以onclick=”f()”调用的时候是调用不到的。
但是如果你在第一段代码中,function f()函数后面加上obj.onclick = f;那程序就又能正常运行了。这是因为直接将函数f绑定给obj对象点击事件上了,所以就不在window.onload()=function(){}的作用域下,就可以成功调用该函数了!

引用文献:http://coolshell.cn/articles/9666.html
http://www.ibm.com/developerworks/cn/web/1308_caiys_jsload/
http://www.bubuko.com/infodetail-695779.html

文章目录