(function(GOVUK, Modules) {
  "use strict";

  GOVUK.timeCache = {};
  GOVUK.resultCache = {};

  var dd = new diffDOM();

  let getter = function(resource, interval, render) {

    if (
      GOVUK.resultCache[resource] &&
      (Date.now() < GOVUK.timeCache[resource])
    ) {
      render(GOVUK.resultCache[resource]);
    } else {
      GOVUK.timeCache[resource] = Date.now() + interval;
      $.get(
        resource,
        response => render(GOVUK.resultCache[resource] = response)
      );
    }

  };

  let poller = (resource, key, $component, interval) => () => getter(
    resource, interval, response => dd.apply(
      $component.get(0),
      dd.diff($component.get(0), $(response[key]).get(0))
    )
  );

  Modules.UpdateContent = function() {

    this.start = function(component) {

      const $component = $(component);
      interval = ($(component).data("interval-seconds") * 1000) || 1500;

      setInterval(
        poller($component.data('resource'), $component.data('key'), $component, interval),
        interval / 5
      );

    };
  };

})(window.GOVUK, window.GOVUK.Modules);

(function(Modules) {
  "use strict";

  var queues = {};
  var dd = new diffDOM();

  var getRenderer = $component => response => dd.apply(
    $component.get(0),
    dd.diff($component.get(0), $(response[$component.data('key')]).get(0))
  );

  var getQueue = resource => (
    queues[resource] = queues[resource] || []
  );

  var flushQueue = function(queue, response) {
    while(queue.length) queue.shift()(response);
  };

  var poll = function(renderer, resource, queue, interval) {

    if (queue.push(renderer) === 1) $.get(
      resource,
      response => flushQueue(queue, response)
    );

    setTimeout(
      () => poll(...arguments), interval
    );

  };

  Modules.UpdateContent = function() {

    this.start = component => poll(
      getRenderer($(component)),
      $(component).data('resource'),
      getQueue($(component).data('resource')),
      ($(component).data('interval-seconds') || 1.5) * 1000
    );

  };

})(window.GOVUK.Modules);

Stop AJAX updates queuing requests
Stop AJAX updates queuing requests

The `updateContent` module updates a section of the page based on an
AJAX request.

The current implementation will poll every `x` seconds. If the server
takes a long time to respond, this results in a the browser queuing up
requests. If a particular endpoint is slow, this can result in one
client making enough requests to slow down the whole server, to the
point where it gets removed from the loadbalancer, eventually bringing
the whole site down.

This commit rewrites the module so that it queues up the render
operations, not the requests.

There is one queue per endpoint, so for
`http://example.com/endpoint.json`:

1. Queue is empty
```javascript
{
  'http://example.com/endpoint.json': []
}
```

2. Inital re-render is put on the queue…
```javascript
{
  'http://example.com/endpoint.json': [
    function render(){…}
  ]
}
```

…AJAX request fires
```
GET http://example.com/endpoint.json
```

3. Every `x` seconds, another render operation is put on the queue
```javascript
{
  'http://example.com/endpoint.json': [
    function render(){…},
    function render(){…},
    function render(){…}
  ]
}
```

4. AJAX request returns queue is flushed by executing each queued
render function in sequence
```javascript
render(response); render(response); render(response);
```
```javascript
{
  'http://example.com/endpoint.json': []
}
```

5. Repeat

This means that, at most, the AJAX requests will never fire more than
once every `x` seconds, where `x` defaults to `1.5`.
