简体   繁体   中英

How to remove a callback registered with a pub/sub datastore?

See the following simple pub/sub-type dataStore which I have implemented:

class DataStore {
    constructor() {
        this.store = {};
        this.callbacks = {};
    }

    getState(key) {
        return this.store[key];
    }

    setState(key, value) {
        this.store[key] = value;
        this.callbacks[key].forEach( callback => {
            callback(this.store[key]);
        });
    }

    onChange(key, callback) {
        this.callbacks[key] = this.callbacks.key || [];
        this.callbacks[key].push(callback);
    }
}

I am trying to figure out how to implement a removeCallback method for this class, and I am not really getting anywhere. I can call filter on the callbacks and use !== to find the exact function and remove it, ie:

removeCallback(key, callback) {
    this.callbacks[key].filter( cb => cb !== callback );
}

--but that approach is dependent on having the callback saved, which I wouldn't. See below:

store.onChange('someValue', val => { /* do something with val */ });
store.removeCallback('someValue', ???);

Since the function passed to onChange was effectively anonymous, how can I identify it?

The caller of removeCallback needs to have something that uniquely identifies the callback. The easiest way would be to store the callback in a variable first:

const cb = val => { /* do something with val */ };
store.onChange('someValue', cb);
store.removeCallback('someValue', cb);

Also note that .filter does not mutate the existing array - you'd need to assign the result of .filter to this.callbacks[key] :

removeCallback(key, callback) {
  this.callbacks[key] = this.callbacks[key].filter( cb => cb !== callback );
}

You also probably want to change

this.callbacks[key] = this.callbacks.key || [];

to

this.callbacks[key] = this.callbacks[key] || [];
                                    ^^^^^

Or, you might use a Set instead, removing the need for .filter and iteration:

onChange(key, callback) {
  this.callbacks[key] = this.callbacks[key] || new Set();
  this.callbacks[key].add(callback);
}
removeCallback(key, callback) {
  this.callbacks[key].delete(callback);
}

If you wanted to be slightly terser, you could have onChange return the passed callback:

const cb = store.onChange('someValue', (val) => { ... });

with

onChange(key, callback) {
  this.callbacks[key] = this.callbacks[key] || new Set();
  this.callbacks[key].add(callback);
  return callback;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM