鲁夫的爱

高效的山寨版DOMNodeInserted 事件

分类: 小小极客    标签: , , , ,     评论: 3人评论

本文内容冗长而繁琐, 总结起来就是几句话:

  1. OpenGG.Clean.Player 的版本号从1.12 开始计算, 因为我觉得5.7 这个版本号跳得太快而功能没有改进, 感情上难以接受.
  2. OpenGG.Clean.Player 现在可以在新浪微博上生效了, 而且性能比之前的版本提高很多, 请及时跟进.
    注: Firefox 12/Chrome 18/Opera 12/搜狗浏览器3.2 测试通过, 而Opera 11及以下的版本无法使用新的工作原理, 性能和功能维持在之前版本的水平.
  3. 改进的技术细节与本文标题有关.


早期的Youku.Tudou.Clean.Player 与现在的版本比起来, 最显著的差距在于是否能替换外链视频播放器, 而实现这个的关键代码来自于Harv.c 的YoukuAntiADs.

document.addEventListener('DOMNodeInserted', onDOMNodeInsertedHandler, false);

这一行代码到底有多重要呢? 我之前在本站的评论区中也跟几个网友交代过: 用脚本去替换页面上已经存在着的播放器, 这是相当简单的工作, 可是怎样在脚本先执行而播放器后插入的情况下替换播放器地址呢, 长期依赖jQuery 的我一直没有一个好的方法来实现, 直到我看到YoukuAntiADs 的这一行代码, 发现了DOMNodeInserted 这个事件.

这一行代码的意思是, 在DOMNodeInserted 事件被触发时, 执行onDOMNodeInsertedHandler 函数. 这样通过绑定DOMNodeInserted 事件, 我们可以实现这样一个效果: 即便脚本先执行而播放器后插入, 我们也可以让onDOMNodeInsertedHandler 函数来替换播放器的地址.

于是, 这才有了可以替换外链播放器的OpenGG.Clean.Player .

可DOMNodeInserted 存在着以下问题:

  1. 性能问题: 网页上所有的元素被插入到document 的时候, 都会触发这个事件, 造成非常严重的性能浪费.
  2. 功能问题: 有的网页并不是直接插入播放器, 而是先插入一个其他元素, 再替换成播放器, 这种情况下DOMNodeInserted 只会在插入时触发而不会在替换时触发, 造成漏网, 一个常见的例子是新浪微博.

之前使用OpenGG.Clean.Player 的同学可能会注意到, 在新浪微博中观看优酷外链视频, 播放器是不会被替换成OpenGG 版的. 要按照YoukuAntiADs 的思路解决这个问题, 必须把DOMNodeInserted 事件换成DOMSubtreeModified 事件. 但后者对性能的浪费比前者还要严重得多. 设想一下这个场景: 插入一个node, 再连续替换其内容, 这只会触发一次DOMNodeInserted , 却会不断地触发DOMSubtreeModified .

问题的关键之处在于, 使用javascript 的时候, 你没有办法像使用css 那样, 让一个行为/表现对后来插入的同一类元素生效. 你能做的只能是绑定一个更宽泛的事件, 比如DOMNodeInserted , 然后当这个事件被触发的时候, 用一个路由函数去过滤不需要的事件目标, 而你所想找到的事件目标只占很小的一个比例 (一个网页上往往有成千上万个元素, 而我们需要寻找的flash 播放器却只有寥寥几个). 当DOMNodeInserted 不够用的时候, 你还得寻找一个比它更宽泛的事件, 比如DOMSubtreeModified , 用更多的性能损耗去实现想要的功能.

直到半小时前, 我读到了这篇文章<I Want a DAMNodeInserted Event!> , 里面提到了一种hack: 用css 给一类目标元素指定一种时间很短的动画效果, 当animationstart 事件被触发时, 执行特定函数. 由于网页上大部分元素都没有动画效果, animationstart 事件被触发的次数将会非常少而精确, 从而提高工作效率. 这个hack 结合了css 全局性 (对后插入的元素同样生效) 和javascript 行为性的优点, 思路非常新颖.

但这个hack 也只是一种无奈之举: animationstart 的效率尽管比DOMNodeInserted 和DOMSubtreeModified 都要高一个甚至若干个数量级, 可等到animation 的使用越来越广泛的时候 (比如一个网页上飘几万朵雪花), 也还是会浪费很大一部分性能. 其最关键的原因还是出在目前前端javascript 这种 listen->fire 的工作方式上, 这有待w3c , 各浏览器厂商和各位geek 继续努力.

本站文章除注明转载外,均为本站原创编译
转载请注明以下信息
文章转载自:鲁夫的爱 [ http://opengg.me/ ]
本文标题:高效的山寨版DOMNodeInserted 事件
本文地址:http://opengg.me/784/high-performance-domnodeinserted-hack/


05-02
2012

无觅相关文章插件,快速提升流量

loading...