.disposer
.disposer(function(any resource, Promise usingOutcomePromise) disposer) -> Disposer
Мета-метод, используемый для указания метода освобождения ресурсов при использовании Promise.using.
Возвращает объект Disposer, который инкапсулирует как ресурс, так и метод его освобождения. Пользователь может передать этот объект в Promise.using для получения доступа к ресурсу при его доступности, а также для обеспечения его автоматического освобождения.
Вторым аргументом, передаваемым в disposer, является результат промиса блока using, который можно проверить синхронно.
Пример:
// This function doesn't return a promise but a Disposer
// so it's very hard to use it wrong (not passing it to `using`)
function getConnection() {
return db.connect().disposer(function(connection, promise) {
connection.close();
});
}
В приведенном выше примере, соединение, возвращаемое getConnection, может использоваться только через Promise.using, как показано ниже:
function useConnection(query) {
return Promise.using(getConnection(), function(connection) {
return connection.sendQuery(query).then(function(results) {
return process(results);
})
});
}
Это гарантирует, что connection.close() будет вызван после разрешения промиса, возвращаемого блоком Promise.using, или если в теле блока произошла ошибка.
Реальный пример:
var pg = require("pg");
// Uncomment if pg has not been properly promisified yet
//var Promise = require("bluebird");
//Promise.promisifyAll(pg, {
// filter: function(methodName) {
// return methodName === "connect"
// },
// multiArgs: true
//});
// Promisify rest of pg normally
//Promise.promisifyAll(pg);
function getSqlConnection(connectionString) {
var close;
return pg.connectAsync(connectionString).spread(function(client, done) {
close = done;
return client;
}).disposer(function() {
if (close) close();
});
}
module.exports = getSqlConnection;
Реальный пример 2:
var mysql = require("mysql");
// Uncomment if mysql has not been properly promisified yet
// var Promise = require("bluebird");
// Promise.promisifyAll(mysql);
// Promise.promisifyAll(require("mysql/lib/Connection").prototype);
// Promise.promisifyAll(require("mysql/lib/Pool").prototype);
var pool = mysql.createPool({
connectionLimit: 10,
host: 'example.org',
user: 'bob',
password: 'secret'
});
function getSqlConnection() {
return pool.getConnectionAsync().disposer(function(connection) {
connection.release();
});
}
module.exports = getSqlConnection;
Примечание о disposers в node
Если метод disposer вызывает ошибку или возвращает отклоненный промис, велика вероятность, что он не смог освободить ресурс. В этом случае у Bluebird есть два варианта — либо игнорировать ошибку и продолжить выполнение программы, либо выбросить исключение (вызывая сбой процесса в node.js).
В Bluebird мы выбрали второй вариант, поскольку ресурсы обычно дефицитны. Например, если соединение с базой данных не может быть освобождено, и Bluebird проигнорирует это, пул соединений быстро исчерпается, и процесс станет непригодным для использования (все запросы, обращающиеся к базе данных, будут ждать вечно). Поскольку Bluebird не знает, как с этим справиться, единственный разумный стандарт — это сбой процесса. Таким образом, вместо бесполезного процесса, который не может обработать больше запросов, мы можем заменить неисправного работника новым, позволяя операционной системе очистить ресурсы.
В результате, если вы ожидаете ошибки или отклонения промиса при освобождении ресурса, вы должны использовать блок try..catch (или Promise.try) и написать соответствующий код обработки ошибок. Если разумно обработать ошибку невозможно, сбой процесса — следующий лучший вариант.
Это также означает, что disposers не должны содержать код, отличный от освобождения ресурсов. Например, вы не можете написать код внутри disposer для подтверждения или отката транзакции, потому что нет механизма для disposer, чтобы сигнализировать об ошибке подтверждения или отката без сбоя процесса.
Для транзакций вместо этого можно использовать аналогичный шаблон:
function withTransaction(fn) {
return Promise.using(pool.acquireConnection(), function(connection) {
var tx = connection.beginTransaction()
return Promise
.try(fn, tx)
.then(function(res) { return connection.commit().thenReturn(res) },
function(err) {
return connection.rollback()
.catch(function(e) {/* maybe add the rollback error to err */})
.thenThrow(err);
});
});
}
// If the withTransaction block completes successfully, the transaction is automatically committed
// Any error or rejection will automatically roll it back
withTransaction(function(tx) {
return tx.queryAsync(...).then(function() {
return tx.queryAsync(...)
}).then(function() {
return tx.queryAsync(...)
});
});
© 2013–2018 Petka Antonov
Licensed under the MIT License.
http://bluebirdjs.com/docs/api/disposer.html