At work and for my own projects I tried to use different promise libraries, for javascript, for java (mostly on android) and of course for haxe. And I absolutely love Bolts library from corporationname (ooops, actually I can’t write it because of BSD license). Anyway, it is good strongly typed (using generics) promise library for java.
Introducing hxbolts! A pure-haxe and cross-platform port of “tasks” component from Bolts.
Imagine you have to delete all comments from blog while player playing in your game, mwahahaha 😈 . But server API has only 4 methods:
- Authorize;
- Get all posts ids;
- Get all comments ids for specific post;
- 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<Void> { 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<Void>) : Void { if (task.isSuccessed) { trace("Everything is good"); } else { trace("Error occurred : " + Std.string(task.error)); } });
Code is linear, easy to understand. It even doesn’t contains try / catch blocks, because hxbolts will take care about exceptions.
More examples at readme file in hxbolts repo.