Reputation: 651
In the following program, when recurse(prog)
is initially called (line 64), it recursively digs into the expressions exp
described in prog
(line 1), switching between the case where exp.type = A, B or C.
At the bottom most level of the recursive call (when case("C")), I am calling verySlowMan(exp.value)
that looks up a list of collections
to check whether a collection with the name of exp.value exists or not.
If yes, the collection is returned
If no, a new Error
is return
The problem is that verySlowMan()
take his time to retrieve a collection.
For simplicity, I made a simple if else
condition, but verySlowMan
will ultimately make an XHR request. So it is unpredictably slow
The question is the following :
How to propagate the return value of verySlowMan all the way up the recursive call to get a nice list of collections as a result of calling recurse(prog) ?
Currently, for understandable reasons, I get [ null, [ null, null ], null ]. But I have really no clue about how to solve it.
I tried to return a deferred.promises from verySlowMan
, but in this case I think recurse() should also return a new promise for each recursive call.
(1) I'm not sure about how to make this properly
(2) I doubt it's the best way
NB : The amount of items in prog
, collections
and the cases in recurse() can potentially become very long.
Here is the program :
var prog = {
type : "A", value : [
{ type : "B", value : "C1" },
{ type : "B", value : [
{ type : "C", value : "C2" },
{ type : "C", value : "end" }
]},
{ type : "B", value : "C3" }
]
}
var collections = [
{ name : "C1", data : ["item1", "item2", "item3"]},
{ name : "C2", data : ["item1", "item2", "item3"]}
]
function verySlowMan( collectionToFind ){
collections.forEach(function(collection){
if ( collection.name === collectionToFind ) {
return collection;
}else{
return new Error("No Collection");
}
});
return null;
}
function recurse(exp){
switch(exp.type){
case("A"):
var As = [];
exp.value.forEach( function(B){
As.push ( recurse(B) );
} );
return As;
break;
case("B"):
var Bs = [];
if (typeof(exp.value) === 'string') {
return verySlowMan( exp.value );
} else {
exp.value.forEach( function(C){
Bs.push ( recurse(C) );
} );
return Bs;
}
break;
case("C"):
return verySlowMan( exp.value );
break;
default:
throw new Error('wrong type');
}
}
console.log( recurse(prog) ); // -> [ null, [ null, null ], null ]
Upvotes: 0
Views: 110
Reputation: 8139
Here is an example with promises.
function verySlowMan( collectionToFind ) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
for(var i = 0; i < collections.length; i++) {
if ( collections[i].name === collectionToFind ) {
resolve(collections[i]);
return;
}
}
reject(new Error("No Collection"));
}, 100);
});
}
function recurse(exp){
function errorHandler(err) {
if(err.message === "No Collection") return null;
else throw err;
};
switch(exp.type){
case("A"):
return Promise.all(exp.value.map(recurse));
case("B"):
if (typeof(exp.value) === 'string') {
return verySlowMan(exp.value).catch(errorHandler);
} else {
return Promise.all(exp.value.map(recurse));
}
case("C"):
return verySlowMan( exp.value ).catch(errorHandler);
default:
return Promise.reject(new Error('wrong type'));
}
}
recurse(prog).then(function(result) {
console.log(result);
}).catch(function(err) {
console.log(err.stack);
});
Upvotes: 1