Remember "const poisoning" in C++, when you would mark one method as const and then you realized you had to mark all the methods it called as const and then all the methods they called, and so on?
I'm having a problem with asynchrony poisoning, in Javascript although I don't think that's relevant, although it propagates up rather than down. When a function might possibly call an asynchronous function, it itself must be re-written as asynchronous, and then all the functions that call it must be and so on.
I don't have a well-formed question here (sorry, mods) but I was hoping someone had either (a) advice or (b) a reference that might have (a).
It's not a bad question. There are a few ways around having to totally trash your flow of control, however. Note: I didn't say it was pretty.
Suppose you have objects A, B, C and D, A.Amethod doesn't return anything and calls a method getBData of B, B calls getCData method of C, and the issue is C was calling D something like so
var data = D.getRawData();
... something to be done with data ...
... something else to be done with data...
and now it has to be written like
D.getData(function(data){
... something to be done with data ...
... something else to be done with data...
});
well, you can always add a callback parameter to each of your methods, so that for the code the code that used to look like:
var A = {
//I'm not recommending coding like this, just for demonstration purposes.
...
Amethod: function(x,y,z){
var somethingForA = this.B.getBData(1,2,3);
astatement1;
astatement2;
...
}
...
}
//end of A
...
var B = {
...
Bmethod: function(x,y,z){
var somethingForB = this.C.getCData(1,2,3);
bstatement1;
var somethingFromB = bstatement2;
return somethingFromB;
}
...
}
//end of B
...
var C = {
...
Cmethod: function(x,y,z){
var somethingForC = this.D.getRawData(1,2,3)
cstatement1;
var somethingFromC = cstatement2;
return somethingFromC;
}
...
}
//end of C
...
You'd now have:
var A = {
...
Amethod: function(x,y,z){
this.B.getBData((1,2,3,function(somethingForA){
astatement1;
astatement2;
});
...
}
...
}
//end of A
...
var B = {
...
Bmethod: function(x,y,z,callback){
this.C.getCData(1,2,3,function(somethingForB){
bstatement1;
var somethingFromB = bstatement2;
callback(somethingFromB);
});
...
}
...
}
//end of B
...
var C = {
...
Cmethod: function(x,y,z,callback){
this.D.getRawData(1,2,3,function(somethingForC) {
cstatement1;
var somethingFromC = cstatement2;
callback(somethingFromC);
});
}
...
}
//end of C
...
That's pretty much a straightforward refactoring using anonymous functions to implement all functionality keeping your flow of control. I don't know how literal a transform that would be; you might have to do some adjustment for variable scope. And obviously, it's not that pretty.
Are there other ways? Sure. As you can see, the above is messy, and we'd hope to keep from writing messy code. How less messy depends upon context.
You don't have to pass a callback parameter, any necessary callback could be passed to the objects beforehand, or it may be passed as one of the items in a parameter. The callback may not need to be directly invoked, but invoked indirectly using one of the various event handling methods available (which you'd have to look at what libraries you might want to use for that), and the data may be passed in when the event is triggered. Or maybe there's a global "DataGetter" that A can register a callback whenever data is "gotten" to completely avoid the intermediaries B and C.
Finally, there's the consideration that if your are knee deep in invocations only to discover you need something that can only be obtained asynchronously, and that data has to be passed up the chain of command, you might be doing something a bit backwards in terms of which objects should control the flow of the program logic (I'm honestly stumped as to how to describe why I seem to think this scenario is problematic, though.). I tend to think, as instances of A have to contain instances of B, B contains instances of C, etc, the instances creating the sub-instances as part of its composition should have some degree of control as to how the sub-instances populate themselves, instead of letting the sub-instances fully decide.... if that makes sense :-(
At this point I feel like I'm rambling a bit so... here's to hoping somebody would explain the issues better than me!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With