首页 > 解决方案 > 如何完全分离/销毁 MutationObserver(可能的内存泄漏)

问题描述

所以我有一个元素(我们称之为“列表”),我使用MutationObserver观察更改(attr 和 childList 添加/删除) 。这个元素有一个“切换”开关,我用它来启用/禁用元素交互和观察。

切换元素与我用来断开观察者的observer.disconnect() 相关联,就像我在切换“ OFF ”时不希望进一步观察一样。

现在,当我想再次交互并“观察”这个元素时,问题就开始了。当我正在查看日志时,似乎在重新连接后(observer.connect(...))。以前的突变仍然保存在记忆中。

我需要正确分离此观察者,因为我还将 POST 请求发送到 mongodb 服务器。有了这个问题,它会导致我的突变列表出现某种膨胀,并且会用更多不必要的 HTTP 请求污染我的 POST 请求。它没有包含在这篇文章中,只是为了上下文而提及。


继续实际代码,请查看我的应用程序的日志和简化的代码结构:

HTML

<div class="list" data-observe="false"> <!-- eventListener attached here, e.g, to ".list" -->
    <div class="list-header">
        <div class="list-toggle-wrap">
            <button class="toggle-btn">Toggle</button>
        </div>
    </div>
    <div class="list-content">
        <!-- observed elements here... -->
    </div>
</div>

JS

const watch = e => {
    if (e.target.matches('.toggle-btn')) {

        const list = e.target.closest('.list')
        const config = {
            attributeFilter: ['value', 'class'],
            attributeOldValue: true,
            childList: true,
            subtree: true,
        }

        const rng = Math.floor(Math.random() * 100)
        const randomHash = () => crypto.randomBytes(6).toString('hex')

        // logging random strings to observe if instance is the same
        console.log(randomHash())

        const callback = mutations => {

            // just logging if mutations are being detected
            console.log(`mutation detected: ${rng}`)

            mutations.forEach(mutation => {
                 // handle mutations
            }
        }

        const observer = new MutationObserver(callback)

        if (list.dataset.observe === 'true') {
            // if observing
            console.log('Observer Disconnected.')
            list.removeEventListener('click', watch)
            observer.disconnect()
            list.dataset.observe = 'false'

        } else if (list.dataset.observe === 'false') {
            // if not observing
            console.log('Observer Connected.')
            list.dataset.observe = 'true'
            observer.observe(list, config)
        }
    }
}

const list = document.querySelector('.list')
list.addEventListener('click', watch)

控制台日志

/* I'm generating these by clicking toggle ON and OFF without mutating
 * anything else
 * 
 * Also do note that I'm filtering uneeded mutations on my callback so
 * it doesn't show/log here, figured I want to mention that since you
 * may ask if this is just some of the actual mutation happening,
 * which is actually not the case
 */

e520c5769d34           list.controller.js:250:12
Observer Connected...  list.controller.js:462:20
mutation detected: 44  list.controller.js:254:16
21cd886b5760           list.controller.js:250:12
Observer Disconnected. list.controller.js:428:20
mutation detected: 44  list.controller.js:254:16
5781b586160c           list.controller.js:250:12
Observer Connected...  list.controller.js:462:20
mutation detected: 44  list.controller.js:254:16
mutation detected: 72  list.controller.js:254:16
29c47a6f6ece           list.controller.js:250:12
Observer Disconnected. list.controller.js:428:20
mutation detected: 44  list.controller.js:254:16
mutation detected: 72  list.controller.js:254:16
797a9dfa19b2           list.controller.js:250:12
Observer Connected...  list.controller.js:462:20
mutation detected: 44  list.controller.js:254:16
mutation detected: 72  list.controller.js:254:16
mutation detected: 52  list.controller.js:254:16
b51b16721df9           list.controller.js:250:12
Observer Disconnected. list.controller.js:428:20
mutation detected: 44  list.controller.js:254:16
mutation detected: 72  list.controller.js:254:16
mutation detected: 52  list.controller.js:254:16
145ba03997a5           list.controller.js:250:12
Observer Connected...  list.controller.js:462:20
mutation detected: 44  list.controller.js:254:16
mutation detected: 72  list.controller.js:254:16
mutation detected: 52  list.controller.js:254:16
mutation detected: 15  list.controller.js:254:16
8acb6fabd173           list.controller.js:250:12
Observer Disconnected. list.controller.js:428:20
mutation detected: 44  list.controller.js:254:16
mutation detected: 72  list.controller.js:254:16
mutation detected: 52  list.controller.js:254:16
mutation detected: 15  list.controller.js:254:16
1a9f20e41cb5           list.controller.js:250:12
Observer Connected...  list.controller.js:462:20
mutation detected: 44  list.controller.js:254:16
mutation detected: 72  list.controller.js:254:16
mutation detected: 52  list.controller.js:254:16
mutation detected: 15  list.controller.js:254:16
mutation detected: 55  list.controller.js:254:16
f4393ece6540           list.controller.js:250:12
Observer Disconnected. list.controller.js:428:20
mutation detected: 44  list.controller.js:254:16
mutation detected: 72  list.controller.js:254:16
mutation detected: 52  list.controller.js:254:16
mutation detected: 15  list.controller.js:254:16
mutation detected: 55  list.controller.js:254:16
762116b899da           list.controller.js:250:12
Observer Connected...  list.controller.js:462:20
mutation detected: 44  list.controller.js:254:16
mutation detected: 72  list.controller.js:254:16
mutation detected: 52  list.controller.js:254:16
mutation detected: 15  list.controller.js:254:16
mutation detected: 55  list.controller.js:254:16
mutation detected: 6   list.controller.js:254:16
and so on...

如您所见,日志显示它每次都是不同的事件实例,但由于某种原因,即使我已经与观察者断开连接,旧的变异引用也会保留。


到目前为止我尝试过的事情。

如果有人能弄清楚这是怎么回事以及我如何垃圾收集/完全取消引用该观察者,我将不胜感激,因此当我切换到ON时,就好像在没有将那些以前的记录保留在内存中的情况下建立了一个新的观察者。

编辑:记录连接/断开连接消息

标签: javascripteventsmemory-leaksgarbage-collectionmutation-observers

解决方案


推荐阅读