我有时会罗嗦:tl;博士:阅读粗体字。
弃用 Mutation Events 背后的动机是众所周知的。它们在完成多种任务方面的功效值得怀疑。
然而,今天,我发现它们的用途高度依赖于那些同样不受欢迎的属性。
我将首先提出问题,然后提出导致我提出问题的原因,因为没有它,这个问题将是荒谬的。
是否可以使用新的 Mutation Observers 让 VM 在更改的瞬间停止(就像 DOM3 Mutation Events 一样),而不是事后向我报告?
基本上,使 Mutation Observer 高效且“合理”的原因在于它的异步性,这意味着(似乎必然)丢弃堆栈,将记录突变推送到列表中,并在下一次将列表传递给合格的观察者滴答声或几个滴答声之后。
我所追求的正是 DOM3 Mutation Event 的堆栈跟踪。我真的很希望这能奏效,但基本上突变事件回调(我可以编写)将有一个堆栈跟踪,它将引导我回到创建我正在监听的元素的实际代码。所以理论上我会写一个像这样的突变事件处理程序:
// NOT in an onload cb
$("div#haystack").on('DOMNodeInserted', function(evt) {
if (is_needle(evt.target)) {
report(new Error().stack); // please, Chrome, tell me what code created the needle
}
});
这给了我黄金答案。
似乎 Mutation Observers 将无法提取此信息。那么,一旦突变事件被完全消除,我该怎么办?它们已经被弃用了一段时间。
现在,更好地解释一下真实的实际情况,以及为什么这很重要。
我一直在试图解决我在这里描述的一个错误:我已经构建了一个完整的 DOM 序列化程序,它可以很好地吐出网页上存在的每个元素,并且在比较它们时,损坏的页面和工作页面是相同的。我已经对此进行了测试,它非常好。它捕获了每一个不同的小东西:无论我的鼠标碰巧悬停在什么地方,因此设置的 CSS 类将反映在 HTML 转储中。如果您搜索它,页面上任何形式的任何文本都会显示出来(前提是它不跨越元素)。所有内联 JS(更重要的是,内联 JS 之间的所有差异)都存在。
然后我继续验证损坏的页面是否缺少几个事件处理程序。因此,没有任何可点击项目响应悬停或点击,因此无法在交互式表单上完成任何有用的工作。这不是唯一的问题,但它确实完全解释了这种行为。鉴于 DOM 在解释行为差异的内联 JS 中没有差异,那么一定是链接资源的内容或元素的不可见属性(事件处理程序属于此类)导致了差异行为。
现在我知道哪些元素应该有处理程序,但我不知道在可笑的大型代码库中(大概:200K 行 JS 全部作为一个资源加载,由几 M 行 Perl 服务器端代码组装)位于分配代码的位置事件。
我尝试了 JS 方法来观察对象属性的修改,例如这个(有很多,但都按照设置 setter 和 getter 的相同原理工作),它第一次有效,然后随后破坏了应用程序。显然分配 setter 和 getter 会导致系统停止运行。我不清楚如何将这种观察属性分配的方法带到我可以获得命中特定元素的代码点列表的地步。这可能是可行的,但如果我只能开火一次,那肯定不行,此后它会破坏一切。
所以用 JS 观察变量就不行了。
我可能能够手动检测 jQuery 本身,这样当我is_needle()
在 jQuery 处理的元素上成功时,我会记录 jQuery 在该元素上执行的所有与事件相关的函数。这太可怕了,如果我的 Mutation Observer 方法失败,我会求助于这个。
当然,还有更多给猫剥皮的方法。我可以getEventListeners()
在目标元素上使用 Handy 来获取其上的事件侦听器函数列表,然后查看那里的代码,并搜索代码库以找到这些函数,然后分析代码以找出这些函数插入事件处理程序的所有位置。这实际上非常简单。