首先我们来认识下这个api,参考自阮一峰的js教程,Mutation Observer 是用来监视DOM元素的变动。类似于事件,做了一个对应操作,触发对应事件的执行,但是它们有着根本之间的区别:事件的执行时同步的,触发的同时,每个事件依次执行,但是observer是异步触发的,等到所有dom操作结束,再执行
Mutation Observer API有如下特点:
1.它等待所有脚本任务完成后,才会运行(即异步触发方式)。 2.它把 DOM 变动记录封装成一个数组进行处理,而不是一条条个别处理 DOM 变动。 4.它既可以观察 DOM 的所有类型变动,也可以指定只观察某一类变动。
来看一个案例,在技术交流群内一个群友遇到的问题,一次冒泡执行的observer触发:
<body>
<div id="1">
<div id="2">
</div>
</div>
</body>
<script>
const id1 = document.getElementById('1')
const id2 = document.getElementById('2')
id1.addEventListener('click',function(){
id1.setAttribute('name', '222')
console.log('1')
})
id2.addEventListener('click',function(){
console.log('2')
id2.setAttribute('name', '222')
})
new MutationObserver(function() {
console.log('11')
}).observe(id2,{
'attributes': true
})
new MutationObserver(function() {
console.log('22')
}).observe(id1,{
'attributes': true
})
id2.click() // 2, 1,11,22
</script>
复制代码
不能理解的地方在于为啥不是这两种情况:
a. 2, 22 , 1 , 11
b. 2, 1, 22 , 11
首先,script根据创建的顺序,将观察者push进观察者数组,也可以说观察者队列。
observer是异步触发,在dom操作之后,而click监听事件又是同步的,每次操作都会同步触发,因此,执行情况是id2元素触发点击冒泡,执行点击事件,修改name值,id2上的observer监听到name变动,将对应观察者标记为待执行。然后是id1元素接收冒泡,执行点击事件,修改name值,同时id2上的observer监听到name变动,也将观察者标记为待执行。
dom操作结束后,遍历观察者数组,依次执行执行待执行的观察者
从上面流程可以明白,a情况肯定是不行的,observer是异步执行。然后,根据队列执行规则,observer回调输出顺序应该是11 , 22。验证一下也很容易,交换observer的创建顺序:
new MutationObserver(function() {
console.log('22')
}).observe(id1,{
'attributes': true
})
new MutationObserver(function() {
console.log('11')
}).observe(id2,{
'attributes': true
})
复制代码
可以看到执行结果为22 ,11