Skip to content

Instantly share code, notes, and snippets.

@Integralist
Last active July 10, 2016 20:27
Show Gist options
  • Save Integralist/d84d65c909eeafe4dfca to your computer and use it in GitHub Desktop.
Save Integralist/d84d65c909eeafe4dfca to your computer and use it in GitHub Desktop.
Functional Programming: Polling XHR
define(['module/bootstrap'], function(news) {
var $ = news.$;
function seconds(secs) {
return secs * 1000;
}
function incrementDelay() {
// don't want the delay to become ridiculous so I set a threshold I don't want it to go beyond
if (delay < threshold) {
delay *= 2;
}
return delay; // we return a value for the sake of our `dispatch` method called by `checkStatus`
}
function exists(value) {
return value !== undefined && value !== null;
}
function dispatch() {
var fns = Array.prototype.slice.call(arguments, 0);
var size = fns.length;
return function(target) {
var ret;
for (var i = 0; i < size; i++) {
var fn = fns[i];
ret = fn.call(fn, target);
if (exists(ret)) {
return ret; // break out of the loop as we've executed a function that doesn't return null
}
}
return ret;
};
}
var checkStatus = dispatch(
function(status) { return status === 304 ? incrementDelay() : null; },
function(status) { return status === 200 ? delay = seconds(5) : null; }
);
function success(data, status, xhr) {
checkStatus(xhr.status);
poll(endpoint);
}
function failure(xhr, status, error) {
incrementDelay();
poll(endpoint);
}
function endpoint() {
$.ajax('http://localhost:3000/foobar', { timeout: limit }).then(success, failure);
}
function poll(endpoint) {
window.setTimeout(endpoint, delay);
}
var limit = seconds(5); // XHR timeout limit
var delay = seconds(5); // timer delay
var threshold = seconds(20); // timer delay threshold
poll(endpoint);
});
@Integralist
Copy link
Author

@danscotton you've been trying out some FP stuff recently I believe. What do you make of this gist?

The purpose of the script is to poll an endpoint (I'm using RoboHydra to dynamically create endpoints) and for every fail or 304 "not modified" status, increase the timeout before attempting to poll the endpoint again. Otherwise, when you do get a healthy 200 status, reset the timeout back down to a regular interval again.

It seems doing Functional Programming for web development is harder than it appears :-/ especially when doing things like XHR and DOM manipulation.

In this script I've tried to keep to the principles of:

  • small functions (but they're not "pure functions" as most don't return a value; also I'm currently not getting much composition out of these functions, but I couldn't see how to achieve that - any suggestions?)
  • pass functions not values (e.g. seconds(5) rather than an ugly direct value of 5000; also I would have preferred to have not referenced the variable delay directly within the poll function but instead passed the value as a function, but that caused more complications and hoops to jump through - I might take another look at it though - any suggestions? also, I could've passed a function into incrementDelay to mutate the delay variable but that seemed more overhead for not a lot of real benefit; maybe I'm not drinking enough of the FP kool-aid? lastly, I'm passing endpoint function as an argument to poll so I don't have a direct reference to endpoint but it feels kind of pointless in this current code sample)
  • swapping conditionals for functions (e.g. dispatch executes each fn in the stack until a truthy value is returned)
  • limit mutations/mutations are ok as long as they are self contained (e.g. the delay variable is only mutated in this single file and isn't a global value - although it would be better if I could limit the mutation even further within this file - again, any suggestions?)

@kenoir
Copy link

kenoir commented Jun 23, 2014

I see what you're up to @Integralist :)

@danscotton
Copy link

This is much harder than I initially thought it would be! The asynchronous nature of the whole thing (both the timeouts and the ajax requests) makes it tricky, and it's hard trying to work out a way of not resorting to storing state in variables across the function calls.

I really like the small seconds and exists functions, and being able to compose your checkStatus method using dispatch seems nice and functional to me. I started trying to think how I would solve this using OO (https://gist.github.com/danscotton/6be0c64188ec1ac42111) to see if that'd help me develop things in a functional way but that didn't really help at all! The main thing I was trying to achieve was to keep the polling behaviour (delays and thresholds) separate from the ajax behaviour (requests, status codes, timeouts).

You don't seem to yield the data from a successful request anywhere either? Is the purposefully not a requirement or would you eventually have to slot that in too?

Here's my attempt at trying to remove the delay variable anyway, and passing it around in callbacks: https://gist.github.com/danscotton/828ee933b2afc0653db1. I just find that doing so litters most methods calls with the parameter, but this just might be my lack of understanding of writing functional code. Really need to read the functional js book! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment