-
-
Save cpdean/8659630 to your computer and use it in GitHub Desktop.
// @cpdean | |
// demonstrates how to have one promise kick off | |
// an additional arbitrary number of promises, and | |
// then merge their results down again after | |
// all the promises are complete. | |
var Q = require('q'); // "q": "~1.0.0" | |
// initial query that generates seed data for more work to be done | |
function fakeQuery(){ | |
var deferred = Q.defer(); | |
setTimeout(function(){ | |
console.log("first query complete"); | |
deferred.resolve([{id: 1}, {id: 2}, {id: 3}]); | |
}, 1e3); | |
return deferred.promise; | |
} | |
// second query | |
function deferredPropertyLookup(x) { | |
var deferred = Q.defer(); | |
setTimeout(function(){ | |
console.log("next query complete on " + x); | |
deferred.resolve(x); | |
}, 1e3); | |
return deferred.promise; | |
} | |
fakeQuery().then(function(results){ | |
// `results` could be an arbitrary number of things | |
// to do more work on | |
// then concurrently run the lookup function with its | |
// post processing step in then() | |
var with_properties = results.map(function(e){ | |
return deferredPropertyLookup(e.id).then(function(found){ | |
return {id: e.id, prop: found}; | |
}); | |
}); | |
return Q.all(with_properties).done(function(a){ | |
// print the results when the lookups and processing are done | |
console.log(a); | |
}); | |
}); |
I lost hours trying to reproduce what they already have!
I wanted to execute promises and non promises in the order and get all the values in the end, so I did this snippet:
http://jsbin.com/vumakumuqu/5/edit
function createGetValue(value) {
return function() {
var q = Q.defer();
Q.delay(1000).then(function() {
q.resolve(value);
});
return q.promise;
};
}
var dict = {};
function valueCollector(identifier, fun) {
return function() {
var result;
result = fun.apply(this, arguments);
if (result.hasOwnProperty('inspect') === false)
result = Q(result);
return result.then(function(value) {
dict[identifier] = value;
return dict;
});
};
}
var a, b, c, d;
a = {
identifier: 'a',
getValue: createGetValue('value of a!')
};
b = {
identifier: 'b',
getValue: createGetValue('value of b!')
};
c = {
identifier: 'c',
getValue: function() {
return 'value of c, no promisses here!';
}
};
d = {
identifier: 'd',
getValue: createGetValue('value of d!')
};
_.reduce(
[a, b, c, d],
function(promiseStack, field) {
field.getValue = valueCollector(field.identifier, field.getValue);
if (promiseStack === null) {
return field.getValue();
} else {
return promiseStack.then(field.getValue);
}
},
null
).then(function(data) {
console.log(data);
})
.fail(function() {
console.log('fuck!');
});
// Returns
//
// {
// a: "value of a!",
// b: "value of b!",
// c: "value of c, no promisses here!",
// d: "value of d!"
// }
When in the end I could do pratically the same with:
Q.all([a.getValue(), b.getValue(), c.getValue(), d.getValue()]).done(function(result){
console.log(result);
});
// Returns
//
// ["value of a!", "value of b!", "value of c, no promisses here!", "value of d!"]
To get the same result, I will just use the same wrapper to return objects instead of values only, and merge then all into one, end of story!
Documentation needs refactoring, also some graphical information, promise system and recursion are better visualized in images I think.
Cheers!
Great example! One that actually works when copy/pasted into a file.
There are some people who think including a line like
var Q = require('q');
is too much distraction.
Here is a snippet I use when I need to run an arbitrary number of promises one at a time sequentially. This is handy if you are making a lot of API calls and don't want to exceed rate or concurrent request limits.
function runPromiseSequence(items) {
return items.map(function(item) {
// Have to wrap this in a function to generate a promise for each item
return function() {
// return a value or promise
return item.doSomethingAsync();
};
}).reduce(Q.when, Q());
}
The function will return a promise chain for each item in the array, like ...then(function(item[0] { ... }).then(function(item[1]) { ... })
etc and you can add to the end of the chain to do something after all the other promises are resolved sequentially.
Great example! Thanks :)
There is one thing I cannot understand. It seems that the only reason you use
fakeQuery
is to pass the array of objects tothen
. Why not just useQ([{id: 1}, {id: 2}, {id: 3}])
instead?