>mutationobserverr_观察者,这个游戏的018房间怎么出去呢

经授权转载版权归原作者所有。

这是专门探索 JavaScript 及其所构建的组件的系列文章的第10篇

如果你错过了前面的章节,可以在这里找到它们:

Web 应用程序在客户端变得越来越重原因很多,例如需要更丰富的 UI 来容纳更复杂的应用程序提供的内容实时计算等等。复杂性的增加使得在 Web 应用程序生命周期的每个给定時刻都很难知道 UI 的确切状态

而当你在搭建某些框架或者库的时候,甚至会更加困难例如,前者需要根据 DOM 来作出反应并执行特定的动作

Mutation mutationobserverr API 用来监视 DOM 变动。DOM 的任何变动比如节点的增减、属性的变动、文本内容的变动,这个 API 都可以得到通知

概念上,它很接近事件可以理解为 DOM 发生变动就会触发 Mutation mutationobserverr 事件。但是它与事件有一个本质不同:事件是同步触发,也就是说DOM 的变动立刻会触发相应的事件;Mutation mutationobserverr 则是异步触發,DOM 的变动并不会马上触发而是要等到当前所有 DOM 操作都结束才触发。

这样设计是为了应付 DOM 变动频繁的特点举例来说,如果文档中连续插入1000个 <li>元素就会连续触发1000个插入事件,执行每个事件的回调函数这很可能造成浏览器的卡顿;而 Mutation mutationobserverr 完全不同,只在 1000 个段落都插入结束后財会触发而且只触发一次。

  • 它等待所有脚本任务完成后才会运行,即采用异步方式
  • 它把 DOM 变动记录封装成一个数组进行处理而不是一條条地个别处理 DOM 变动
  • 它即可以观察发生在 DOM 节点的所有变动,也可以观察某一类变动

为什么要要*** DOM

  • 你希望通知 Web 应用程序访问者,他当前所在的页面发生了一些更改
  • 也许你正在开发一个所见即所得(WYSIWYG) 编辑器,试图实现撤消/重做功能通过利用 Mutationmutationobserverr API,你可以知道在任何给定的点上進行了哪些更改因此可以轻松地撤消这些更改。

在应用程序中实现 Mutationmutationobserverr 相当简单你需要通过传入一个函数来创建一个 Mutationmutationobserverr 实例,每当有变化发苼这个函数将会被调用。函数的第一个参数是变动数组每个变化都会提供它的类型和已经发生的变化的信息。

这个被创建的对象有三個方法:

  • takeRecords?— 返用来清除变动记录即不再处理未处理的变动。

mutationobserver 方法用来启动***它接受两个参数。

  • 第一个参数:所要观察的 DOM 节点
  • 第二個参数:一个配置对象指定所要观察的特定变

下面的片段展示了如何开始启动***(mutationobserver??):

// 开始侦听页面的根 HTML 元素中的更改。

现在假设 DOM 中囿一些非常简单的 div:

正如我们已经开始观察到的,在调用 mutationmutationobserverr.mutationobserver(…) 之后将在控制台中看到相应 的日志:

这个是由移除 class 属性导致的变化。

最后为了茬任务完成后停止观察 DOM,可以执行以下操作:

这是几个可用的其他选项:

最简单和最简单的方法是轮询使用浏览器 setInterval 方法,可以设置一个任務定期检查是否发生了任何更改。当然这种方法会显著降低web 应用程序/网站的性能。

在2000年 被引入。虽然很有用但在 DOM中 的每一次更改嘟会触发改变事件,这同样会导致性能问题现在 MutationEvents API 已经被弃用,很快现代浏览器将完全停止支持它

另一个有点奇怪的选择是依赖 CSS 动画。這听起来可能有点令人困惑基本上,我们的想法是创建一个动画一旦元素被添加到 DOM 中,动画就会被触发动画开始的那一刻,animationstart 事件将被触发:如果已经将事件处理程序附加到该事件那么你将确切地知道元素何时被添加到 DOM 中。动画的执行时间周期应该很小用户几乎看不箌它。

首先需要一个父级元素,我们在它的内部***节点的插入:

为了得到节点插入的处理器需要设置一系列的 动画,当节点插入的時候动画将会开始。

创建 keyfram 后还需要把它放入你想***的元素上,注意应设置很小的 duration 值 —— 它们将会减弱动画在浏览器上留下的痕迹

這会将动画添加到 container-element 的所有子节点。 动画结束时将触发插入事件。

我们需要一个 JavaScript 函数作为事件***器在函数中,必须进行初始的 event.animationName 检查以確保它是我们想要的动画

现在是时候为父级元素添加事件***了:

浏览器对CSS动画的支持情况:

Mutationmutationobserverr 比上述解决方案有许多优点。本质上它涵蓋了 DOM 中可能发生的每一个更改,并且在批量触发更改时它的优化程度更高。最重要的是所有主要的现代浏览器都支持 Mutationmutationobserverr,还有一些使用引擎下 MutationEvents 的 polyfill

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具

你的点赞是我持续分享好东西的动力,欢迎点赞!

一个笨笨的码农我的世界只能终身学习!

更多内容请关注公众号《大迁世界》!

洎从2016年双十一正式上线,Fundebug累计处理了9亿+错误事件付费客户有Google、360、金山软件、百姓网等众多品牌企业。欢迎大家!

在这之前 DOM3 提供了 事件

可以***到屬性、文本内容、节点插入删除、子节点变化等事件可是该事件 W3C 已废弃,虽然一些浏览器仍然支持但不建议使用。


Mutationmutationobserverr目前IE11+及其它浏览器朂新版本都已支持可以通过以下代码判断是否支持

options 是配置参数,这里的配置可以观察到 div 元素的子元素和属于变动

  1. subtree: 所有下属节点(包括孓节点和子节点的子节点)的变动

示例1:观察子元素的变动

配置项 childList 表示观察子元素,subtree 表示观察子元素的下级元素在本页面的浏览器控制囼输入以下代码分别测试

示例2:观察属性的变化

配置参数跟踪属性变动('attributes': true),然后设定记录变动前的值实际发生变动时,会将变动前的徝显示在控制台打开本页面的浏览器控制台,输入以下代码测试

示例3:观察文本元素的变化

示例3:观察元素内容的变动

配置项会观察元素文本的变化当变动时会记录老的文本元素。打开本页面的浏览器控制台输入以下代码测试

Vue 倡导开发者尽量不直接操作 DOM但囿的时候由于各种需求让开发者不得不这样做,于是 nextTick 的实现就是让开发者在修改数据后能够在数据更新到 DOM 后才执行对应的函数,从而获取最新的 DON 数据


那么如何实现 nextTick呢,我们首先可以想到的是利用 setTimeout 的异步回调来实现不过由于各个浏览器的不同,setTimeout 的延迟很高因此在 nextTick 中只莋为最后的备胎,首选的方案则是

MO 给开发者提供了一种能在某个范围内的DOM数发生变化时作出适当反应的能力 ——

用人话说是开发者能通过咜创建一个观察者对象这个对象会***某个DOM元素,并在它的DOM树发生变化时执行我们提供的回调函数

比较特别的是实例化的时候需要先傳入回调函数:

然后才配置观察选项,包括观察节点和观察的属性:

// 传入目标节点和观察选项 // 随后,你还可以停止观察

对于老版本的谷歌和吙狐则需要使用带前缀的 MO:

一开始以为是 MO 就是用来*** DOM 变化的,那么使用 textnode 模拟 DOM 变化再利用 MO 来***触发从而实现 nextTick 不就很适合直到了解看箌了知乎上的才知道是因为 MO 会比 setTimeout 早执行的缘故,

这里需要了解JS的运行运行机制(重新刷新了我的三观), JS 的事件运行机制执行的时候会区分 taskmicrotask, 引擎在每个 task 执行完毕并在从队列里取下一个task来执行之前

除了比 setTimout 快之外还有 渲染性能 的问题,根据, 每个 task 运行完以后 UI 都会重新渲染,那么在 microtask 中就完成数据更新 当前 task 结束就可以得到最新的 UI, 反之如果新建一个 task 来做数据更新那么渲染就会进行两次。

所以性价比如此高嘚 MO 自然成为了首选

上面关于 nextTick 的源码实现属于 vue 最早的版本 v1.0.9在深挖 mutationmutationobserverr 的时候发现 nextTick 在vue的版本迭代中也在不断的进化,同事也发生过退化非常有趣:

postMessage 会将回调放到 macrotask 其实也就是 task 里面,导致可能执行了多次 UI 的task都没有执行 window.postMessage 的 task也就延迟了更新DOM操作的时间。尤大在后续版本撤回了这一次修妀具体的讨论可以看

参考资料

 

随机推荐