MaxHoper
MaxHoper

Reputation: 35

Listen for change using MutationObserver?

I have a script that uses setInterval to check for some object state, but it cause a little bit of lag and I was wondering whether I could use an MutationObserver?

My setInterval:

var checkExist = setInterval(function() {
    var life = 300;
    var games = Game.currentGame.ui.playerPetTick.health;
    if (games < life) {
        console.log("It exists")
        clearInterval(checkExist);
    }
}, 100); // check every 100ms

My observer attempt:

var target = Game.currentGame.ui.playerPetTick.health;

var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
        console.info("It exists");
    });    
});

var config = { attributes: true, childList: true, characterData: true };

observer.observe(target, config);

Could this be done?

Upvotes: 2

Views: 599

Answers (2)

Julius Dzidzevičius
Julius Dzidzevičius

Reputation: 11000

I suggest to use setters and getters (MutationObserver, as I wrote in comment is used only for Node objects). And because property as I assume from your code, might be of various types (object, string, etc.) I suggest to use lodash isEqual method - it accepts arrays, objects, strings, numbers, etc. so you don't need to write compare function for every type. Very handy function.

You can also install only this particular function.

Here I made a function where you can pass your object and property name to be watched for changes:

var isEqual = require('lodash.isequal');

function watchChanges(object, prop, primaryValue) {
  object[`_${prop}`] = primaryValue;
  Object.defineProperty(object, prop, {
   get() { return object[`_${prop}`] },
   set(newValue) { 
    if ( !isEqual(object[`_${prop}`] , newValue)) {
      console.log('change maded in prop')
    }
    object[`_${prop}`] = newValue;
    },
  });
}

To inspect what happens, here is an equivalent function for primitive types:

function watchChanges(object, prop, defaultValue) {
  object[`_${prop}`] = defaultValue;
  Object.defineProperty(object, prop, {
   get() { return object[`_${prop}`] },
   set(newValue) { 
    if ( object[`_${prop}`] !== newValue) {
      console.log('change maded in', prop, 'was', object[`_${prop}`], 'is', newValue)
    }
    object[`_${prop}`]  = newValue;
    },
  });
}

ob = {a: 1, b:1, c:1};
watchChanges(ob, 'a', ob.a);

ob.a = 2;
ob.a = 3;

Upvotes: 1

likle
likle

Reputation: 1797

The MutationObserver won't help you here, since your object does not seem to be a DOM node. But you can easily implement some kind of object observing using getters/setters or proxy objects. A simple example:

var playerInfo = {
  set health(newValue) {
    this._health = newValue;
    if (this.onhealthchange) {
      this.onhealthchange(newValue);
    }
  },

  get health() {
    return this._health;
  }
};

playerInfo.onhealthchange = function(newValue) {
  console.info("Health changed: " + newValue);
};

playerInfo.health = 4;

Upvotes: 1

Related Questions