有啥方法可以找出 MutationObserver 是不是断开连接或观察?

Posted

技术标签:

【中文标题】有啥方法可以找出 MutationObserver 是不是断开连接或观察?【英文标题】:Any way to find out whether a MutationObserver is disconnected or observing?有什么方法可以找出 MutationObserver 是否断开连接或观察? 【发布时间】:2018-02-10 21:08:40 【问题描述】:

this 似乎显示了完整的方法列表。

显然,找到解决这个问题的方法并不难......但为了优雅,应该有一个方法isConnected,不是吗?

【问题讨论】:

也许有道理,但它不在specification中。 一个可能的猜测是您可以将观察者连接到多个事物,因此简单的 isConnected 布尔标志不会那么有用。 @loganfsmyth 如果你这样做 disconnect 你当然会断开它与一切的联系......但这当然不是全部,我理解你的意思:也许应该有一个getNumberOfObservedTargets 函数?... 或者就此而言 getObservedTargets... 这真的很有用。 我想问题是,你用这个标志做什么?它不能用于检查“我是否需要调用 .observe”,因为可能已经有其他节点的观察者,并且使用它来检查“我需要调用 .disconnect”没有用,因为您可以调用.disconnect 以确保。观察者的数量本身没有用,getObservedTargets 可能会暴露您不希望暴露的信息。好像又回到了用例,你还没有澄清。 在过去的几个小时里,我已经完全重新考虑/重新设计了所有内容,所以目前我不需要它。但大多数侦听器设计模式并不是那么隐秘。然而,我对MutationObserver 最大的不满是,当它被触发时,您无法获得堆栈跟踪......并且由于异步调用回调,这意味着您无法找到导致 DOM 突变的代码位。 【参考方案1】:

如果人们真的想知道 MutationObserver 对象实例的状态,那么获得它的一种方法是以组合样式从它创建一个新的对象类 (JSFiddle example):

// to keep actual working methods of the class out of the object's instance whenever possible
// is a good practice, but since ECMAScript2015 (ES2015, ES6) does not support private methods
// (though does support private variables with "var" in constructors), IIFE (Immediately-invoked
// function expression) has to be used to encapsulate, isolate the full class definition:
let UpgradedMutationObserver = (function() 

        // private variable/property to store the instance's current status; WeakMap is used to improve memory 
        // management as it sheds its value pairs as soon as the instance is not reference any more:
  const _targetsArrayWeakMap = new WeakMap(), // new WeakMap([[this, []]]) would not work as "this" here is a window object
        // private method-function wrapper that provides access for the object's instance to class prototype
        // methods as well as to an earlier-declared private variable;
        // this wrapper is designed as a function factory as it returns functions that get assigned to the object
        // instance's public methods:
        _callPrototypeMethod = function(prototypeMethod, instance, args)
        
          // actual type of the private variable/property is set here; runs only once:
          if (typeof _targetsArrayWeakMap.get(instance) === 'undefined')
          
            _targetsArrayWeakMap.set(instance, []);
           
          return function()
          
            const returnedObject = Object.getPrototypeOf(instance)[prototypeMethod](instance, _targetsArrayWeakMap.get(instance), ...arguments);
            _targetsArrayWeakMap.set(instance, returnedObject.privateVariable);
            return returnedObject.returnValue;
          
        ;
  class UpgradedMutationObserver
  
    constructor(callback)
    
      // an arrow function version of the way to attach the object's instance would not need .bind(this)
      // as there is no own "this" in arrow functions, "this" would mean the instance of the object
      this.MutationObserver = new MutationObserver(function( ...args)
      
        return callback( ...args, this);
      .bind(this)); 
      this.observe = _callPrototypeMethod('observe', this, arguments); // bind(this);
      this.disconnect = _callPrototypeMethod('disconnect', this, arguments); //.bind(this);
      this.isConnected = _callPrototypeMethod('isConnected', this, arguments); //.bind(this);
      // ... other standard methods like takeRecords() can also taken care of, if necessary
    
    observe(instance, targetsArray, targetObserve, optionsObserve)
     
      // many targets can be observed, though callback function is always the same
      // for the same instance of (Upgraded)MutationObserver:
      instance.MutationObserver.observe(targetObserve, optionsObserve); 
      // before adding targetObserve to the list of observed,
      // it is checked that it exists (at least for now):
      if (document.contains(targetObserve))
      
        targetsArray.push(targetObserve);
      
      return privateVariable: targetsArray;
    
    disconnect(instance, targetsArray)
     
      // the method stops observation of all targets at once
      instance.MutationObserver.disconnect();
      targetsArray = [];
      return privateVariable: targetsArray;
    
    isConnected(instance, targetsArray, targetToCheck)
    
      // in case of observed nodes removed from DOM (destroyed), they are filtered out:
      targetsArray = targetsArray.filter(function(e)
      
        return document.contains(e);
      );
      // maximum versatily of return results is provided 
      // all while maintaining false/"truthy" quasi-boolean dichotomy:
      return 
                privateVariable: targetsArray,
                returnValue: targetsArray.length == 0
                ? false
                : (targetToCheck
                   ? targetsArray.includes(targetToCheck)
                   : targetsArray)
             ;
    
  
  return UpgradedMutationObserver;
)();  

console.log('UpgradedMutationObserver: ____________________________________________________________');
const observer = new UpgradedMutationObserver(function(mutationsList, observer)

  console.log('UpgradedMutationObserver callback: processing of an added node', mutationsList, observer);
);
console.log('UpgradedMutationObserver initialized as "observer": ', observer);
console.log('UpgradedMutationObserver: observer.isConnected(): ', observer.isConnected()); 

console.log('UpgradedMutationObserver: observer.observe(document.documentElement, childList: true, subtree: true)...'); 
observer.observe(document.documentElement, childList: true, subtree: true);

// logs "Array [ html....]"
console.log('UpgradedMutationObserver: observer.isConnected(): ', observer.isConnected()); 

console.log('UpgradedMutationObserver: observer.observe(document.body, childList: true, subtree: true)...'); 
observer.observe(document.body, childList: true, subtree: false);

// logs "Array [ html. ..., body. ...]"
console.log('UpgradedMutationObserver: observer.isConnected(): ', observer.isConnected()); 

// logs "true":
console.log('UpgradedMutationObserver: observer.isConnected(document.documentElement): ', observer.isConnected(document.documentElement)); 

var div = document.querySelector('div'), childDiv, i;
for (i = 1; i < 5; i++)

  setTimeout(function()
  
    if (this < 4)
    
      childDiv = document.createElement('div');
      div.appendChild(childDiv);
      console.log("a child DIV is added after " + this + "s delay for UpgradedMutationObserver to discover");
    
    else
    
      console.log('UpgradedMutationObserver: observer.disconnect()...'); 
      observer.disconnect();
      // logs "false" as nothing is observed:
      console.log('UpgradedMutationObserver: observer.isConnected(): ', observer.isConnected()); 
    
  .bind(i), i * 1000);


【讨论】:

令人印象深刻。我目前还没有机会检查它是否像我希望的那样运行,但感谢您不厌其烦地设计它! 我使用了这个类的不同版本来让 MutationObserver 知道当前的鼠标坐标(通过将事件监听器附加到 shell 类的新属性),所以它应该可以工作。通过使用这种组合风格,您可以根据自己的喜好创建各种特殊的对象类。最困难的部分是第一次制作,但之后,它可以很容易地修改。 (编辑:添加到 JSFiddle 的链接,更改类结构以使实际工作方法属于类原型而不是实例。)

以上是关于有啥方法可以找出 MutationObserver 是不是断开连接或观察?的主要内容,如果未能解决你的问题,请参考以下文章

可以用来监听Dom类名样式变化的方法: MutationObserver

有啥方法或方法可以找出我的错误以获取此命令的解决方案吗?

有啥方法可以找出专辑何时被添加到 web api 的 spotify 中?

有啥方法可以在 laravel 5.6 中找出路由文件的当前路径? [复制]

MutationObserver监控DOM变化

有啥简单的方法可以在不进行反序列化的情况下从 json 中找出最低值 c#