Home Java After all the asynchronous calls

After all the asynchronous calls

by admin

So, we are writing an application with a bunch of asynchronous requests. We need to send two asynchronous requests and process their result only after we get the result of both of them. For example, it could be an asynchronous file request and a database request, the result of which needs to be put together and processed. Or two adjax queries.
But the peculiarity of asynchronous requests is that we don’t know which one will come first and which one will come last. There are different ways to solve this, but I haven’t seen a nice and graceful one yet. In this thread I’ll tell you how I see it.

var process = processFsAndDb.after('fs', 'db');asyncFsAccess( file, process.fs);asyncDbAccess(query, process.db);

Usually act on one of the following options :

You may get lucky

Usually only people who don’t understand asynchronous calls can do that. Something like this :

var fileData = null;asyncFsAccess( file, function (data) {fileData = data;});asyncDbAccess(query, function (dbData) {processFsAndDb(fileData, dbData);});

Let’s imagine that the file system access was a bit slow and the query from the base came faster. Then there will be nothing in fileData, although we just didn’t get that data! Sadly…

Whatever, I’ll wait.

Another option is at least reliable. Make one request, wait until it completes, make a second request.

asyncFsAccess( file, function (fileData) {asyncDbAccess(query, function (dbData) {processFsAndDb(fileData, dbData);});});

This is better than hoping for the best, but here we sacrifice time – the database could already be searching while the file system is being accessed, but no, we have to sit back and wait. And, in the case of Ajax, the user will have to wait twice as long for a response. Not good

7 times check

Flagging system or variable checking. After each query, check the flag corresponding to it, and if all flags are checked, execute.

var fileData = dbData = null;asyncFsAccess( file, function (data) {fileData = data;if (fileData dbData)processFsAndDb(fileData, dbData);});asyncDbAccess(query, function (data) {dbData = data;if (fileData dbData)processFsAndDb(fileData, dbData);});

But not very nice. The code is repetitive, flags need to be added in many places. If you have to send three simultaneous requests it will be a lot of text

7 times check ++

var fileData = dbData = null;var process = function () {if (fileData dbData)processFsAndDb(fileData, dbData);};asyncFsAccess( file, function (data) {fileData = data;process();});asyncDbAccess(query, function (data) {dbData = data;process();});

This is better, but also not very nice. Flags are repeated 4 times (count the number of fileData variables)

My variant, extending the prototype

The resulting code is :

var process = function (args) {processFsAndDb(args.fs, args.db);}.after('fs', 'db');asyncFsAccess( file, process['fs']);asyncDbAccess(query, process['db']);

Or, even like this :

var process = processFsAndDb.after('fs', 'db');asyncFsAccess( file, process.fs);asyncDbAccess(query, process.db);

In essence we will use the variant with flags, but abstract it under a method, which we will add to the prototype function :

Function.prototype.after = function () {/*** @var onReady is our function which will be executed after all calls are completed* @var after is a hash of functions to be executed.* it is its properties that we pass as colbocks (process.fs and process.db)* @var ready - this is where we will store the responses of each function and when all the keys, * that are in after will also be here - so it's time to call onReady*/var onReady = this, after = {}, ready = {};var checkReady = function () {for (var i in after) if (!(i in ready)) return;onReady(ready);};for (var i = 0, l = arguments.length; i < l; i++) {(function (key) {after[key] = function () {ready[key] = arguments;checkReady();};})(arguments[i]);}return after;};

I think this is a pretty handy and nice enough way for such a rare but important task.

You may also like