I want to use the when.map
function to process some data.
After the data is processed I need to do some cleanup (e.g. release the currently used database connection back to the connection pool).
The problem with my approach using catch
and finally
is that finally
is called when the first reject
occurs, and while other mappings are still in progress.
So how can I wait until all of the mapping promises are finished, so that it is possible to do a save cleanup.
require('when/monitor/console');
var when = require('when');
function testMapper(value) {
console.log('testMapper called with: '+value);
return when.promise(function(resolve, reject) {
setTimeout(function() {
console.log('reject: '+value);
reject(new Error('error: '+value));
},100*value);
});
}
when.map([1,2,3,4],testMapper)
.then(function() {
console.log('finished')
})
.catch(function(e) {
console.log(e);
})
.finally(function() {
console.log('finally')
});
Output
testMapper called with: 1
testMapper called with: 2
testMapper called with: 3
testMapper called with: 4
reject: 1
[Error: error: 1]
finally
reject: 2
[promises] Unhandled rejections: 1
Error: error: 2
at null._onTimeout (index.js:9:14)
reject: 3
[promises] Unhandled rejections: 2
Error: error: 2
at null._onTimeout (index.js:9:14)
Error: error: 3
at null._onTimeout (index.js:9:14)
reject: 4
[promises] Unhandled rejections: 3
Error: error: 2
at null._onTimeout (index.js:9:14)
Error: error: 3
at null._onTimeout (index.js:9:14)
Error: error: 4
at null._onTimeout (index.js:9:14)
Environmentinformation:
Your best bet is to go with when.settle
, settle returns all promises when they resolve, not when they fulfill so you can manually check which one did well and which one did not.
var arrayOfPromises = array.map(testMapper);
when.settle(arrayOfPromises).then(function(descriptors){
descriptors.forEach(function(d){
if(d.state === "rejected"){
// do cleanup for that promise, you can access its rejection reason here
// and do any cleanup you want
} else{
// successful results accessed here
console.log("Successful!", d.value);
}
})
});
Note:
This is actually not a small problem. When I say not a small problem, what I mean is that it's a huge problem that's really hard to solve correctly. There are multiple implied behaviors here and edge cases.
Consider reading this somewhat lengthy discussion.
If you're willing to consider - Bluebird has an experimental promise-using
branch that allows specifying disposers, which would let you do this rather easily.
You would be able to do:
using(pool.getConnectionAsync().disposer("close"), function(connection) {
return connection.queryAsync("SELECT * FROM TABLE");
}).then(function(rows) {
console.log(rows);
});
Or in the multiple resource case:
var a = Promise.cast(externalPromiseApi.getResource1()).disposer("close");
var b = Promise.cast(externalPromiseApi.getResource2()).disposer("close");
using(a, b, function(resource1, resource2) {
// once the promise returned here is resolved, we have a deterministic guarantee that
// all the resources used here have been closed.
})
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