观察目标节点上尚不存在的突变
Observe mutations on a target node that doesn't exist yet
是否可以在 DOM 节点上观察尚不存在的突变?
示例:
我的应用程序在某个时候创建了一个 div:<div id="message" data-message-content="foo" data-message-type="bar" />
。
我想关注这个div的创造和变化。
var mutationObserver = new MutationObserver(function(mutations){
// Some code to handle the mutation.
});
mutationObserver.observe(
document.querySelector('#message'),
{
attributes: true,
subtree: true,
childList: true,
characterData: false
}
);
);
现在这个returns一个错误因为#message
是空的(div还没有被创建)。
Failed to execute 'observe' on 'MutationObserver': parameter 1 is not of type 'Node'.
一个明显的解决方案是观察 body
并检查是否有任何突变是 div#Message
的创建,但这似乎是个坏主意/或者可能对性能不利。
只能观察到一个已存在的节点。
但别担心,因为 getElementById 与枚举所有突变的添加节点相比快得离谱,等待元素出现根本不会像您在 Devtools -> Profiler 面板中看到的那样费力。
function waitForAddedNode(params) {
new MutationObserver(function(mutations) {
var el = document.getElementById(params.id);
if (el) {
this.disconnect();
params.done(el);
}
}).observe(params.parent || document, {
subtree: !!params.recursive || !params.parent,
childList: true,
});
}
用法:
waitForAddedNode({
id: 'message',
parent: document.querySelector('.container'),
recursive: false,
done: function(el) {
console.log(el);
}
});
始终使用 devtools 探查器并尝试使您的观察者回调消耗的时间少于 CPU 时间的 1%。
- 尽可能观察未来节点的直接父节点 (
subtree: false
)
- 在 MutationObserver 回调中使用 getElementById、getElementsByTagName 和 getElementsByClassName,避免使用 querySelector,尤其是极慢的 querySelectorAll。
- 如果在 MutationObserver 回调中 querySelectorAll 是绝对不可避免的,首先执行 querySelector 检查,平均而言这样的组合会快得多。
- 不要在 MutationObserver 回调中使用需要回调的数组方法,如 forEach、filter 等,因为在 Javascript 中,与经典的
for (var i=0 ....)
循环和 MutationObserver 相比,函数调用是一项昂贵的操作回调可能每秒触发 100 次,在复杂的现代页面上的每批突变中有数十、数百或数千 addedNodes
。
- 不要在 MutationObserver 回调中使用 the slow ES2015 loops 之类的
for (v of something)
除非你进行转译并且生成的代码运行速度与经典 for
循环一样快。
是否可以在 DOM 节点上观察尚不存在的突变?
示例:
我的应用程序在某个时候创建了一个 div:<div id="message" data-message-content="foo" data-message-type="bar" />
。
我想关注这个div的创造和变化。
var mutationObserver = new MutationObserver(function(mutations){
// Some code to handle the mutation.
});
mutationObserver.observe(
document.querySelector('#message'),
{
attributes: true,
subtree: true,
childList: true,
characterData: false
}
);
);
现在这个returns一个错误因为#message
是空的(div还没有被创建)。
Failed to execute 'observe' on 'MutationObserver': parameter 1 is not of type 'Node'.
一个明显的解决方案是观察 body
并检查是否有任何突变是 div#Message
的创建,但这似乎是个坏主意/或者可能对性能不利。
只能观察到一个已存在的节点。
但别担心,因为 getElementById 与枚举所有突变的添加节点相比快得离谱,等待元素出现根本不会像您在 Devtools -> Profiler 面板中看到的那样费力。
function waitForAddedNode(params) {
new MutationObserver(function(mutations) {
var el = document.getElementById(params.id);
if (el) {
this.disconnect();
params.done(el);
}
}).observe(params.parent || document, {
subtree: !!params.recursive || !params.parent,
childList: true,
});
}
用法:
waitForAddedNode({
id: 'message',
parent: document.querySelector('.container'),
recursive: false,
done: function(el) {
console.log(el);
}
});
始终使用 devtools 探查器并尝试使您的观察者回调消耗的时间少于 CPU 时间的 1%。
- 尽可能观察未来节点的直接父节点 (
subtree: false
) - 在 MutationObserver 回调中使用 getElementById、getElementsByTagName 和 getElementsByClassName,避免使用 querySelector,尤其是极慢的 querySelectorAll。
- 如果在 MutationObserver 回调中 querySelectorAll 是绝对不可避免的,首先执行 querySelector 检查,平均而言这样的组合会快得多。
- 不要在 MutationObserver 回调中使用需要回调的数组方法,如 forEach、filter 等,因为在 Javascript 中,与经典的
for (var i=0 ....)
循环和 MutationObserver 相比,函数调用是一项昂贵的操作回调可能每秒触发 100 次,在复杂的现代页面上的每批突变中有数十、数百或数千addedNodes
。 - 不要在 MutationObserver 回调中使用 the slow ES2015 loops 之类的
for (v of something)
除非你进行转译并且生成的代码运行速度与经典for
循环一样快。