Asynconsistency

javascript |

Because it is trivial to pass around functions in JavaScript, asynchronous programming comes easy. However, it’s equally easy to write code that results in unpredictable execution order.

For example, it wouldn’t be that odd to see a method like this on some object:

method: function(callback) {
    if (this.condition) {
        callback();
    } else {
        var client = new XMLHttpRequest();
        client.open("GET", "http://example.com/", true);
        client.onreadystatechange = function() {
            if (client.readyState === 4) {
                callback();
            }
        }
        client.send(null);
    }
}

With this method, the caller can’t be certain if the callback will be called before the return or after. Instead, this method should be written like this:

method: function(callback) {
    if (this.condition) {
        // always return before calling callback
        setTimeout(callback, 0);
    } else {
        var client = new XMLHttpRequest();
        client.open("GET", "http://example.com/", true);
        client.onreadystatechange = function() {
            if (client.readyState === 4) {
                callback();
            }
        }
        client.send(null);
    }
}

This makes for predictable code flow, which is particularly important when a callback changes some shared state.

obj.method(changeEverything);
// I'm guaranteed that everything hasn't changed yet

Related Posts (see all)

Topology Preserving Simplification Comments
Mocking the file system Comments
AngularJS Whitespace Guide Comments