javascript基础学习系列二百三十六:异步回调与记录队列

MutationObserver 接口是出于性能考虑而设计的,其核心是异步回调与记录队列模型。为了在 大量变化事件发生时不影响性能,每次变化的信息(由观察者实例决定)会保存在 MutationRecord 实例中,然后添加到记录队列。这个队列对每个 MutationObserver 实例都是唯一的,是所有 DOM 变化事件的有序列表。

1. 记录队列

调用 MutationObserver 实例的 takeRecords()方法可以清空记录队列,取出并返回其中的所 4 有 MutationRecord 实例。看这个例子:
每次 MutationRecord 被添加到 MutationObserver 的记录队列时,仅当之前没有已排期的微任 务回调时(队列中微任务长度为 0),才会将观察者注册的回调(在初始化 MutationObserver 时传入) 作为微任务调度到任务队列上。这样可以保证记录队列的内容不会被回调处理两次。
不过在回调的微任务异步执行期间,有可能又会发生更多变化事件。因此被调用的回调会接收到一 个 MutationRecord 实例的数组,顺序为它们进入记录队列的顺序。回调要负责处理这个数组的每一 个实例,因为函数退出之后这些实现就不存在了。回调执行后,这些 MutationRecord 就用不着了, 因此记录队列会被清空,其内容会被丢弃。

2. takeRecords()方法

   let observer = new MutationObserver(
    (mutationRecords) => console.log(mutationRecords));
observer.observe(document.body, { attributes: true });
document.body.className = 'foo';
document.body.className = 'bar';
document.body.className = 'baz';
console.log(observer.takeRecords()); console.log(observer.takeRecords());
// [MutationRecord, MutationRecord, MutationRecord]
// []

这在希望断开与观察目标的联系,但又希望处理由于调用 disconnect()而被抛弃的记录队列中的 MutationRecord 实例时比较有用。

性能、内存与垃圾回收

DOM Level 2 规范中描述的 MutationEvent 定义了一组会在各种 DOM 变化时触发的事件。由于 浏览器事件的实现机制,这个接口出现了严重的性能问题。因此,DOM Level 3 规定废弃了这些事件。 10 MutationObserver 接口就是为替代这些事件而设计的更实用、性能更好的方案。
将变化回调委托给微任务来执行可以保证事件同步触发,同时避免随之而来的混乱。为 Mutation- Observer 而实现的记录队列,可以保证即使变化事件被爆发式地触发,也不会显著地拖慢浏览器。
无论如何,使用 MutationObserver 仍然不是没有代价的。因此理解什么时候避免出现这种情况 就很重要了。

1. MutationObserver 的引用

MutationObserver 实例与目标节点之间的引用关系是非对称的。MutationObserver 拥有对要
观察的目标节点的弱引用。因为是弱引用,所以不会妨碍垃圾回收程序回收目标节点。 然而,目标节点却拥有对 MutationObserver 的强引用。如果目标节点从 DOM 中被移除,随后
被垃圾回收,则关联的 MutationObserver 也会被垃圾回收。

2. MutationRecord 的引用

记录队列中的每个 MutationRecord 实例至少包含对已有 DOM 节点的一个引用。如果变化是 childList 类型,则会包含多个节点的引用。记录队列和回调处理的默认行为是耗尽这个队列,处理 每个 MutationRecord,然后让它们超出作用域并被垃圾回收。
有时候可能需要保存某个观察者的完整变化记录。保存这些 MutationRecord 实例,也就会保存 它们引用的节点,因而会妨碍这些节点被回收。如果需要尽快地释放内存,建议从每个 MutationRecord 中抽取出最有用的信息,然后保存到一个新对象中,最后抛弃 MutationRecord。

  • 23
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: HTML DOM,即HTML文档对象模型,是一种用于访问和操作HTML文档中元素的标准方法。在JavaScript中,可以使用DOM来查找、修改、添加和删除HTML元素。在本教程中,我们将学习如何使用DOM来操作HTML文档的元素。 ### 回答2: JavaScript学习手册十四:HTML DOM——文档元素的操作(二)介绍了文档元素的一些高级操作,包括插入和删除节点、替换节点、复制节点等。下面我将详细介绍这些操作的用法和注意事项。 首先是插入节点,包括appendChild()和insertBefore()方法。appendChild()方法可以将一个节点追加到某个元素的子节点列表的末尾,而insertBefore()方法可将一个节点插入到元素的指定位置。这两个方法都可以接收字符串、元素、文本节点等参数,可以将它们转换为节点后插入。需要注意的是,插入节点后必须重新获取元素才能正确地操作修改后的DOM树。 接下来是删除节点,包括removeChild()和replaceChild()方法。removeChild()方法可以移除指定节点,replaceChild()方法则可将指定节点替换为另一个节点。调用这两个方法也需要重新获取元素。 另外,还有cloneNode()和hasChildNodes()方法。cloneNode()方法可以复制一个节点,包括节点的属性、事件、插入的子节点等,但不包括子节点的引用和事件处理程序。hasChildNodes()方法可判断节点是否包含子节点。 需要注意的是,在使用这些高级DOM操作时,应尽可能减少DOM的操作次数。因为频繁操作DOM可能会导致性能问题,因此应该尽可能缓存和重用DOM元素,同时避免频繁更新DOM。此外,在修改DOM树时,应当小心操作,避免影响网页布局和用户体验。 总之,JavaScript学习手册十四:HTML DOM——文档元素的操作(二)提供了一些高级操作DOM树的方法,可以方便地插入、删除、替换和复制节点。合理地使用这些方法,可以为网页的构建、交互和流畅度提供帮助。 ### 回答3: HTML DOM是JavaScript操作HTML和XML的接口,它将HTML和XML文档表示为具有层次结构的节点树,通过对节点树进行操作,可以实现对文档元素的增删改查。之前我们已经学习了文档元素的遍历和属性的操作,本篇文章将进一步介绍如何对文档元素进行插入、替换和移除操作。 文档元素的插入操作,可以通过createElement()方法创建一个元素节点,然后通过appendChild()将该节点插入到指定的父节点下。还可以使用insertBefore()方法在指定位置插入节点,该方法需要指定要插入的节点和插入位置的参考节点。同时还可以使用insertAdjacentHTML()方法直接插入HTML代码并将其转换为节点。 文档元素的替换操作,可以通过replaceChild()方法实现,该方法需要指定要替换的节点和替换后的新节点。替换操作可以用于更新页面中的元素,比如将旧的图片替换成新的图片等。 文档元素的移除操作,可以通过removeChild()方法实现,该方法需要指定要移除的节点,并将其从父元素节点中删除。还可以使用remove()方法直接将元素节点从页面中删除。 在进行文档元素操作时,需要注意避免对页面结构造成破坏,比如插入重复的元素或删除父元素节点等操作。另外,DOM操作可能会影响页面的性能,因此在实际应用中需要谨慎处理。 总的来说,HTML DOM提供了丰富的接口,可以实现对文档元素的灵活操作,帮助我们更好地控制和管理页面内容。对于Web前端开发者而言,熟练掌握HTML DOM操作技巧是非常重要的一项技能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值