Poor man's realtime
Streaming to browsers has got a lot easier with the advent of APIs like WebSockets and Server-sent Events. However the server-side aspect is often trickier to setup--many servers and runtimes are not tuned for long-lived requests.
There's a much simpler approach to 'realtime' updates which can be applicable in some situations; polling the page's endpoint and updating the body's HTML. I put realtime in quotes because this is not strictly realtime. However it's a good enough technique for a lot of cases. Indeed we're using it to update a progress bar and list of results in Mailmatch.
All we need to do is set up an interval to re-fetch the page's HTML every five seconds, parse the response HTML looking for a specific element, and then replace the page's corresponding element with the updated one from the server.
$ = jQuery class @Reloader constructor: (@selector = '.wrapper', @path, @interval = 5000) -> @start() start: => @timer = setInterval(@fetch, @interval) stop: => clearInterval(@timer) fetch: => $.get(@path).done(@render) render: (data) => $body = $(@parseBody(data)) if @selector is 'body' $el = $body else $el = @findAll($body, @selector) $(@selector).replaceWith($el) parseHTML: (html) => $.parseHTML(html, document, false) parseBody: (data) => @parseHTML(data.match(/<body[^>]*>([\s\S.]*)<\/body>/i)) findAll: ($elems, selector) -> $elems.filter(selector).add($elems.find(selector))
Notice we're having to parse out the
<body> tag using a regex--document fragments don't like parsing out doctypes. Also notice that by default,
undefined -- jQuery's Ajax request will just fetch the page's current path and query parameters.
To use the library, simply instantiate it on document ready, passing in a selector to the element that you want to constantly update.
$ -> new Reloader('.el-wrapper')
This technique is better than full page reload since it's a lot quicker - it doesn't entail fetching all the styles and scripts in the header. It also has the advantage of localizing updates to a specific element.