I've read about the promise disposer pattern in several places but I can't figure out what it is. It was suggested to me to use it in code that looks like:
function getDb(){
return myDbDriver.getConnection();
}
var users = getDb().then(function(conn){
return conn.query("SELECT name FROM users").finally(function(users){
conn.release();
});
});
What's the promise disposer pattern and how does it apply here?
Note - in native promises, I shim .finally
as "add both rejection and fulfillment handlers that return the value but perform an action". I'm using bluebird in this case if it matters.
The problem with the above approach is that if you forget releasing the connection after every single time you perform getDb
you have a resource leak that might freeze your app eventually when it runs out of the resource you're leaking.
You might, in one place do:
var users = getDb().then(function(conn){
return conn.query("SELECT name FROM users");
});
Which will leak a database connection that was never closed.
The disposer pattern is a way to couple a scope of code with owning the resource. By binding the resource to a scope we make sure it is always released when we're done with it and we can't easily forget to release it. It is similar to using
in C#, with
in Python and try-with-resource in Java as well as RAII in C++.
It looks like:
withResource(function(resource){
return fnThatDoesWorkWithResource(resource); // returns a promise
}).then(function(result){
// resource disposed here
});
If we wrote our code as:
function withDb(work){
var _db;
return myDbDriver.getConnection().then(function(db){
_db = db; // keep reference
return work(db); // perform work on db
}).finally(function(){
if (_db)
_db.release();
});
}
We could write our above code as:
withDb(function(conn){
return conn.query("SELECT name FROM users");
}).then(function(users){
// connection released here
});
Examples of users of the disposer pattern are sequelize and knex (bookshelf's query builder). It's also possible to use it for simpler things like hiding a loader when all AJAX requests completed for instance.