Separate concerns with queues

When you’re doing Javascript, you often find yourself listening to events, and then taking action upon what happened. Let’s take a classic example; the drag and drop effect. You have code that listens for the mousedown event which should signal that it’s time to start listening for the mousemove event. In the mousemove event listener code, you probably have code to calculate positions, check if the drag is within boundaries, etc. And then code to actually move the element so the drag effect can be achieved. Something like this in psuedo code:

function onMousedown(e) {
  initDrag(e);
}
function initDrag(e) {
  document.onmousemove = onMousemove;
}
function onMousemove(e) {
  element.style.top = e.pageY +'px';
  element.style.left = e.pageX +'px';
}

But I would suggest that the code to reposition the element should be moved away from the event listener. Not just moving that code into it’s own function, and let the event listener call that function (even though that’s a good thought). Instead, let’s create a queue:

function onMousedown(e) {
  initDrag(e);
}
function initDrag(e) {
  document.onmousemove = onMousemove;
}
var new_positions = [];
function onMousemove(e) {
  new_positions.push({top: e.pageY, left: e.pageX});
}

And then code to process the queue:

var paint_interval = setInterval(
  function() {
    if(new_positions.length) {
      var pos = new_positions.shift();
      element.style.top = pos.top +'px';
      element.style.left = pos.left +'px';
    }
  },
  50
);

So what’s the use of this? Doesn’t it just add unnecessary complexity? In this very simple example it sure does, but there’s still a beauty in it since we are separating concerns. On one side, there’s code that listens to what the user wants to happen, and adds that to the queue. On the other side, there’s code that decides whether to actually listen to what the user wants to do, or to deny it, and the two sides doesn’t need to know about the other.
You could add logic in the queue processing function (the function in the interval) that checks if the queue is too large, and then ignore the first 10 queue items and move directly to number 11, which would save the browser having to paint those 10 steps and move directly to number 11.
Another reason could be that you only want to allow the element to move X number of pixels per run, regardless of how fast the user drags, and then eventually catch up with the mouse position. Or if you have a lot of stuff going on, and you don’t care if the dragging is smooth, you can change the interval to run 5 times per second, instead of 20.

This is essentially the Command Pattern, except that a Command is executable in itself, and my queue items are just data holders, and it’s up to the queue processor to make sense of that data. The Command pattern is more general, as any command can be added to the queue/stack, and thesehere queues are more specialized, since all queue items are of the same type.

So the point is to separate logic, and decouple different parts of your application to make them more isolated. The queue processing doesn’t care where a queue item comes from, it’s only concern is to process the queue. That enables you to add queue items from other parts of the application as well, and the code that listens to mousemove events doesn’t need to be touched.
That enables you to let your application grow and meet new requirements without making a mess of the code with lots if nested if statements, since you have separated logic. If nothing else, you can impress other people by telling them about your fancy queue processing architecture. It probably won’t impress beautiful women at your local bar though.


About this entry