Manager that collects and handles multiple tasks that run on events like window.scroll, window.resize etc I'm working on a website where different things can occur on resize and scroll events. I only want one event handler that comes into play, whenever something in the DOM must be changed.

So I created a TaskManager where you can register objects and callbacks, that are run, when the specific event is fired.

The TaskManager is injected into other objects, where this.taskManager.registerTask() is called to send all necessary information.

The TaskManager then executes all registered tasks, as soon as an event occurs. It also sends the current scrollTop-value to the callback.



class TaskManager {
  constructor() {
    this.DOM = {
      html: document.getElementsByTagName('html')[0],
    }

    this.tasks = {
      scroll: [],
      resize: [],
    };

    window.addEventListener('scroll', event =&gt; {
      window.requestAnimationFrame(timestamp =&gt; {
        this.processTasksOnScroll();
      });
    });
  }

  registerTask(type, task) {
    if (!this.tasks[type]) {
      return false;
    }

    this.tasks[type].push(task);
    return true;
  }

  processTasksOnScroll() {
    const scrollTop = window.scrollY || window.scrollTop || this.DOM.html.scrollTop;

    for (const task of this.tasks.scroll) {
      task.target[task.callback](scrollTop);
    }
  }
}

class Test {
  constructor(config) {
    this.taskManager = config.taskManager || null;

    if (this.taskManager) {
        this.taskManager.registerTask('scroll', {target: this, callback: 'onScroll'});
    }
  }

  onScroll(scrollTop) {
    console.log('Callback in Test with scrollTop: ' + scrollTop);
  }
}

const taskManager = new TaskManager();
const test = new Test({taskManager: taskManager});
.test {
  height: 120vh;
  padding: 20px;
  background: rgba(0, 0, 0, 0.2);
  text-align: center;
}
&lt;div class="test"&gt;Scroll here …&lt;/div&gt;




Is this a good approach or could something be improved?
Some points.


window is the default object. You don't need to use is. It is highlighted by the fact you don't use it sometimes window.document, or window.TaskManager but then for objects you are unsure of window.addEventListener you add it.
It is not a good idea to stack requestAnimationFrame requests. 


Events related to mouse movements can fire at rates much higher than the display refresh rate of 60fps.
It introduces an up to 16ms delay on the event (and yes users will notice it as a sluggish response). 
If used in conjunction with standard event handlers you will be handling events out of order. 
Completely decouples the handler from the event.

You have decoupled (ignoring above point) the event from the handler because you don't pass on the event object. If you are going to manage events you should pass on the event object so that the handler can access the event.
registerTask will happily push events to the stack without checking if the supplied object is a valid. When you come to handling the event eg processTasksOnScroll it will throw if task.target or task.callback do not result in a function reference. If it throws none of the following events will be handled.
If any of the tasks throws an uncaught error then all following tasks will not be called.


Without knowing more about the project its hard to say more about this approch.

I do feel personally that events should not be one to many. For each event object created there should be one unbroken execution path that completely handles the event. Having events trigger more events is just going to result in an unmanageable mess, as you add code to conditional communicate between handlers wanting priority, or exclusivity.

That is not to say you can not have one handler for many events and then selectively redirect the event to a specific handler.