Fetch, Promise, Observables

I just published a new JSHackerNews app to my website at https://widgetwonk.azurewebsites.net/OtherStuff/JsHackerNews. It’s very simple. Like another app I wrote before, it queries Hacker News for the top stories and displays them. But actually it queries a proxy I use. The proxy queries the Hacker News API and introduces errors, random delays, timeouts and such. This makes it more visible that my app handles failures gracefully.

The real point of this app though was to practice using the new JavaScript native APIs fetch and promise. If you are reading this, you probably know that in JavaScript for a long time the native api for handling AJAX was built on the function XMLHttpRequest. I guess that function was built before people started to love promises, so it’s not build that way. It uses events and event handlers. Everyone has hated using XMLHttpRequest forever, so people immediately began writing libraries to abstract it away. For a long time everybody used the AJAX utility that came bundled with jQuery for some reason. More recently, there was AngularJS that had it’s own build-in $http server. Those are both based on or at least can be used in the promise paradigm.

Only very recently did the JavaScript spec-writers develop a nice, promise based API for http requests. This also came along with including promises in the spec for the first time. Before this JavaScript did not have any native promises. We used Kris Kowal’s q mainly. (By the way, I still like q better than the native API. It seems more robust, but that’s for another time.)

So, as I said, my main goal was to practice these new APIs. On top of that, I decided not to use any JavaScript libraries or frameworks at all for my own code. The only external JavaScript I included was polyfills for the APIs. Fetch and Promise and still very new, and I expect only the very latest browsers support them well. Quite a lot of the world is still using Internet Explorer 10 for some reason.

This was a fun experiment. Along the way I decided I wanted something like an RxJS Observable, but of course I was not going to import RxJS. I found it was fairly easy to wrap my own Observable constructor in like 16 lines of code as follows:

module.exports = function Observable (subscribeFunction) {
    let self = this;
    this.subscriberUpdateFunction = function() {}
    this.observer = {
        next : function(val) {
            self.subscriberUpdateFunction(val);
        }
    };
    this.subscribe = (subFunction) => {
        this.subscriberUpdateFunction = subFunction
        subscribeFunction(this.observer);
    }
    this.next = function(val) {
        this.subscriberUpdateFunction(val);
    }
}

Sigh. Note how my first thought was to write a constructor function—not a class. The class in JavaScript is just syntactic sugar. Those of us who have been writing JavaScript for ten years have gotten along just fine without them for a long time.

The entire source for my project is here: https://github.com/xerocross/js-hacker-news . It’s not great. If anything, it is an example of how crappy web apps looked before we had AngularJS. Back then the same file might even have PHP snippets injected directly into the JavaScript. That was one of the early ways that data from the backend got sent to the client. Also, one had to bind buttons to functions explicitly. One had to somehow capture updates to the data and write imperative functions for how those changes were to change the view. I could have tried to write something cleaner, to keep business logic separated from view logic. But that would basically just mean writing a small subset of the Vue library myself from scratch. That did not sound like fun. So here you have an intermingled mess of business logic and view logic in one file.

It works though. It even works in a durable, reliable, and expressive way despite calling an API that is intentionally buggy.

Also, in the future I’ll probably use my 16-line Observable above far more often than I will import the RxJS library.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s