hxbolts

Deal with async tasks like a boss

View project on GitHub

Logo

hxbolts is a port of a "tasks" component from java library named Bolts. A task is kind of like a JavaScript Promise, but with different API.

While original java library is about keeping long-running operations out of the UI thread, current version of hxbolts is more about transforming async callback hell into nice looking code.

Installation

haxelib install hxbolts

Let's talk

Imagine you have to delete all comments from blog while player playing in your game, mwahahaha 😈 . But server API has only 4 methods:

  1. Authorize;
  2. Get all posts ids;
  3. Get all comments ids for specific post;
  4. Delete specific comment by id.

Let you have a function for making async requests:

private static function makeRequestAsync(
    url : String,
    callback : String -> Void
) : Void { ... }

Usually code will look like:

var token : String = null;

makeRequestAsync("http://blog.tld/api/authorize?user=me", function(result : String) : Void {
    try {
        token = Reflect.field(Json.parse(result), "token");
    } catch (e : Dynamic) {
        trace("Error occurred : " + Std.string(e));
        return;
    }

    makeRequestAsync('http://blog.tld/api/postsIds?token=${token}', function(result : String) : Void {
        var ids : Array<Int>;

        try {
            ids = cast Json.parse(result);
        } catch (e : Dynamic) {
            trace("Error occurred : " + Std.string(e));
            return;
        }

        var results = new Array<String>();

        for (id in ids) {
            makeRequestAsync('http://blog.tld/api/commentsIds?token=${token}&postId=${id}', function(result : String) : Void {
                results.push(result);

                if (results.length == ids.length) {
                    // ...
                }
            });
        }
    });
});

Uh oh... And I don’t even started deletion process.

hxbolts coming to the rescue!

At first we need to boltify makeRequestAsync function:

private static function makeRequestTask(url : String) : Task<String> {
    var tcs = new TaskCompletionSource<String>();

    makeRequestAsync(url, function(result : String) : Void {
        tcs.setResult(result);
    });

    return tcs.task;
}

The rest is easy:

var token : String = null;

makeRequestTask("http://blog.tld/api/authorize?user=me").onSuccessTask(function(task : Task<String>) : Task<String> {
    token = Reflect.field(Json.parse(task.result), "token");
    return makeRequestTask('http://blog.tld/api/postsIds?token=${token}');
}).onSuccessTask(function(task : Task<String>) : Task<Array<String>> {
    var tasks = new Array<Task<String>>();

    for (id in (cast Json.parse(task.result) : Array<Int>)) {
        tasks.push(makeRequestTask('http://blog.tld/api/commentsIds?token=${token}&postId=${id}'));
    }

    return Task.whenAllResult(tasks);
}).onSuccessTask(function(task : Task<Array<String>>) : Task<Nothing> {
    var tasks = new Array<Task<String>>();

    for (response in task.result) {
        for (id in (cast Json.parse(response) : Array<Int>)) {
            tasks.push(makeRequestTask('http://blog.tld/api/deleteComment?token=${token}&commentId=${id}'));
        }
    }

    return Task.whenAll(tasks);
}).continueWith(function(task : Task<Nothing>) : Nothing {
    if (task.isSuccessed) {
        trace("Everything is good");
    } else {
        trace("Error occurred : " + Std.string(task.error));
    }

    return null;
});

Code is linear, easy to understand. It even doesn’t contains try / catch blocks, because hxbolts will take care about exceptions.

Check out more examples at hxbolts repo.