Ручное обещание pg.связаться с Блюберд
Я хочу предложить метод node-postgres pg.connect
наряду с внутренним методом connection.query
, предусмотренным в обратном вызове.
Я могу .promisify
последнее, но мне нужно реализовать первое вручную (если я что-то упустил, пожалуйста, объясните).
Дело в том, что я не уверен, является ли этот код правильным или его следует улучшить? Код работает, я просто хочу знать, использую ли я Bluebird, как подразумевалось.
// aliases
var asPromise = Promise.promisify;
// save reference to original method
var connect = pg.connect.bind(pg);
// promisify method
pg.connect = function (data) {
var deferred = Promise.defer();
connect(data, function promisify(err, connection, release) {
if (err) return deferred.reject(err);
// promisify query factory
connection.query = asPromise(connection.query, connection);
// resolve promised connection
deferred.resolve([connection,release]);
});
return deferred.promise;
};
4 ответа:
Выбросьте весь этот ужасный код обратного вызова, а затем сделайте это где-нибудь в инициализации приложения:
var pg = require("pg"); var Promise = require("bluebird"); Object.keys(pg).forEach(function(key) { var Class = pg[key]; if (typeof Class === "function") { Promise.promisifyAll(Class.prototype); Promise.promisifyAll(Class); } }) Promise.promisifyAll(pg);
Позже в любом месте вы можете использовать модуль pg, как если бы он был разработан для использования обещаний, чтобы начать с:
// Later // Don't even need to require bluebird here var pg = require("pg"); // Note how it's the pg API but with *Async suffix pg.connectAsync(...).spread(function(connection, release) { return connection.queryAsync("...") .then(function(result) { console.log("rows", result.rows); }) .finally(function() { // Creating a superfluous anonymous function cos I am // unsure of your JS skill level release(); }); });
К настоящему времени существует ряд библиотек, которые делают это для вас:
- pg-promise - общие обещания/A+ для PG
- postgres-bluebird
- dbh-ph
- pg-bluebird
Обновление для bluebird 3:
Вызов
pg.connectAsync(...).spread(function(connection, release) { ... })
больше не будет работать, потому что API bluebird изменился: http://bluebirdjs.com/docs/new-in-bluebird-3.html#promisification-api-changes .Проблема в том, что
promisifyAll
в bluebird 3 не обрабатывает несколько аргументов по умолчанию. Это приводит к тому, что вызов.spread()
сообщает о TypeError следующим образом:TypeError: expecting an array or an iterable object but got [object Null]
Чтобы решить эту проблему, можно явно включить несколько аргументов для
connect
/connectAsync
. Делать следующее после всего многообещающего материала, упомянутого выше:... pg.connectAsync = Promise.promisify(pg.connect, { multiArgs: true });
Предлагаю немного видоизменить решение Петьки Антонова
var Promise = require('bluebird'); var pg = require('pg'); Object.keys(pg).forEach(function (key) { var Cls = null; try { Cls = pg[key]; if (typeof Cls === 'function') { Promise.promisifyAll(Cls.prototype); Promise.promisifyAll(Cls); } } catch (e) { console.log(e); } }); Promise.promisifyAll(pg);
Здесь
'pg[key]
завернут вtry-catch
блок, потому чтоpg[key]
может ретранслироватьerror
при попытке доступа кpg['native']