First, I must apologize for the code atrocity you are about to see.
I am writing a SOAP web service in NodeJS using the SOAP module.
My question is: Is there a way to execute code after multiple asynchronous methods have completed?
My code is the following
var http = require('http');
var soap = require('soap');
var strategyService = {
Strategy_Service: {
Strategy_Port: {
getOptions: function(args, callback) {
var source = "";
var destination = "";
var taxi = false;
var shuttle = false;
var bus = false;
var taxiResponse = "N/A";
var shuttleResponse = "N/A";
var busResponse = "N/A";
if (args.source.$value != undefined){
source = args.source.$value;
destination = args.destination.$value;
taxi = getBoolean(args.taxi.$value);
shuttle = getBoolean(args.shuttle.$value);
bus = getBoolean(args.bus.$value);
} else {
source = args.source;
destination = args.destination;
taxi = getBoolean(args.taxi);
shuttle = getBoolean(args.shuttle);
bus = getBoolean(args.bus);
}
var url;
var args = {"tns:source":source, "tns:destination":destination};
if (taxi){
url = "http://localhost:8001/wsdl?wsdl";
soap.createClient(url, function(err, client){
client.Taxi_Service.Taxi_Port.takeTaxi(args, function(err, result){
if (err) throw err;
taxiResponse = result.message.substring(0, result.message.length);
if (!bus && ! shuttle){
callback({
taxi: taxiResponse,
bus: busResponse,
shuttle: shuttleResponse
});
}
if (bus){
url = "http://localhost:8003/wsdl?wsdl";
soap.createClient(url, function(err, client){
client.Bus_Service.Bus_Port.takeBus(args, function(err, result){
if (err) throw err;
busResponse = result.message.substring(0, result.message.length);
if (!shuttle){
callback({
taxi: taxiResponse,
bus: busResponse,
shuttle: shuttleResponse
});
}
if (shuttle){
url = "http://localhost:8002/wsdl?wsdl";
soap.createClient(url, function(err, client){
client.Shuttle_Service.Shuttle_Port.takeShuttle(args, function(err, result){
if (err) throw err;
shuttleResponse = result.message.substring(0, result.message.length);
callback({
taxi: taxiResponse,
bus: busResponse,
shuttle: shuttleResponse
});
})
})
}
})
})
} else if (shuttle){
url = "http://localhost:8002/wsdl?wsdl";
soap.createClient(url, function(err, client){
client.Shuttle_Service.Shuttle_Port.takeShuttle(args, function(err, result){
if (err) throw err;
shuttleResponse = result.message.substring(0, result.message.length);
callback({
taxi: taxiResponse,
bus: busResponse,
shuttle: shuttleResponse
});
});
});
}
});
});
} else if (bus){
url = "http://localhost:8003/wsdl?wsdl";
soap.createClient(url, function(err, client){
client.Bus_Service.Bus_Port.takeBus(args, function(err, result){
if (err) throw err;
busResponse = result.message.substring(0, result.message.length);
if (!shuttle){
callback({
taxi: taxiResponse,
bus: busResponse,
shuttle: shuttleResponse
});
}
if (shuttle){
url = "http://localhost:8002/wsdl?wsdl";
soap.createClient(url, function(err, client){
client.Shuttle_Service.Shuttle_Port.takeShuttle(args, function(err, result){
if (err) throw err;
shuttleResponse = result.message.substring(0, result.message.length);
callback({
taxi: taxiResponse,
bus: busResponse,
shuttle: shuttleResponse
});
})
})
}
});
});
} else if (shuttle){
url = "http://localhost:8002/wsdl?wsdl";
soap.createClient(url, function(err, client){
client.Shuttle_Service.Shuttle_Port.takeShuttle(args, function(err, result){
if (err) throw err;
shuttleResponse = result.message.substring(0, result.message.length);
callback({
taxi: taxiResponse,
bus: busResponse,
shuttle: shuttleResponse
});
});
});
} else {
callback({
taxi: taxiResponse,
bus: busResponse,
shuttle: shuttleResponse
});
}
}
}
}
}
var xml = require('fs').readFileSync('StrategyService.wsdl', 'utf8'),
server = http.createServer(function(request,response) {
response.end("404: Not Found: "+request.url)
});
server.listen(8000);
soap.listen(server, '/wsdl', strategyService, xml);
getBoolean = function(string){
lowerCase = string.toLowerCase();
if (lowerCase == "true" || lowerCase == "t" || lowerCase == "1"){
return true;
} else {
return false;
}
}
In my defense, I will say that this is my first attempt at creating a SOAP service using NodeJS, and I am fairly new to NodeJS as well.
A brief explanation of what I've done
The first if else block is because I use SoapUI as well as NodeJS to test my server, and they seem to pass the data in different ways.
Then, the disgusting beast of nested if else blocks. This is because the callback method is executed at the end of an asynchronous function, but there seems to be no way (that I'm aware of) to execute a function with the condition that multiple asynchronous functions have given a response.
What I've tried
I first tried to set a variable in the callback of the different methods. For instance
fun1(args, callback){
fun1Finished = true;
callback();
}
fun2(args, callback){
fun2Finished = true;
callback();
}
while (!fun1Finished || !fun2Finished){
// code gets stuck here until fun1 and fun2 are finished
}
fun3(args, callback){
// do stuff that requires both functions to be finished
callback();
}
That didn't work, so then I decided to write a series of nested callbacks such as
fun1(args, callback){
// do stuff
callback(
// now fun2 will be executed after fun1
fun2(args, callback){
// do more stuff
callback(
// now fun3 will be executed after fun2, which was executed after fun1
fun3(args, callback){
// do stuff that requires both fun1 and fun2 to be finished
callback();
}
);
}
);
}
That code does indeed work, but it's uglier than all get out, and I hate it.
Any suggestions are much appreciated, and code examples help me more than anything.
If you are interested in looking at all the project files, you can view them on my github.