DOM
(Document Object Model),文档对象模型
document.readyState 和 readystatechange
因为有了DOMContendLoaded
和load
事件更能在页面DOM
加载完成和页面所有资源加载完成的时候被准确的触发。所以,readystatechange
事件已经不太常用。
最近在看sea.js
的源码,发现这个事件在IE6-8
浏览器上可以作为以上两个事件的替代品,因为在IE6-8
,以上两个事件有些时候并不能按照我们的预期执行。
并且,在所有浏览器中,document
上是都有readystatechange
和readyState
属性的,但是在具体element
上,只有IE
上有这个事件和属性。
在sea.js
中,需要在页面中插入一个script
标签,在script
远程加载并执行后,及时的触发script
的load
事件。因为可能同时插入多个script
标签,要保证每个脚本的插入顺序和load
事件的触发顺序一致,但在IE6-8
中,却并不能保证。
但是,好巧不巧。在IE6-8
中,如果当前script
中的代码正在执行,那么这个script
的readyState
属性值会变成interactive
,因为浏览器只会单线程执行代码,所以当前执行的script
只会有一个。从而可以模拟load
事件,达到目的。
sea.js
之所以要保证顺序,是因为它会把每个script
(模块)的信息保存在一个临时变量中,在script
代码执行完成后,设置script
的src
属性为这个
模块的标识符,然后置空这个变量,移除这个script
,继续下一个。因为只有这个一个临时变量,所以必须保证执行顺序和事件触发顺序的同步。
document.createDocumentFragment
如果你要向DOM
中插入很多个子节点。可以先把这些子节点插入到一个空白节点中,最后将这个空白节点插入到DOM
中,这样可以减少页面reflow
,节约性能。
批量插入DOM
1
2
3
4
5
6
7
8
9
10
11
12var arr = []
var len = 5
for(var i = 0; i < len; i++) {
var el = document.createElement(div)
el.textContent = i
arr.push(el)
}
// 会引起5次 reflow
for(var j = 0; j < len; j++) {
document.body.appendChild(arr[j])
}
使用document.createDocumentFragment
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16var arr = []
var len = 5
for(var i = 0; i < len; i++) {
var el = document.createElement(div)
el.textContent = i
arr.push(el)
}
var blank = document.createDocumentFragment()
for(var j = 0; j < len; j++) {
blank.appendChild(arr[j])
}
// 只会引起一次reflow
document.body.appendChild(blank)
这个原理跟使用「JS操作CSS尽量操作类名而不是具体style」的方法一样,只不过后者减少的是页面的repaint
。
直接操作单个属性1
2
3
4
5
6var el = document.getElementById('app')
// 引起3次 repaient
el.style.color = '#000'
el.style.fontSize = '18px'
el.style.fontWeight = 'bold'
操作类名1
2
3
4var el = document.getElementById('app')
// 引起一次 repaient
el.className += ' test'
1 | .test { |