如何使用 Bluebird 在构造函数上承诺导出的函数 "class"

How to use Bluebird to promisify the exported functions on a constructor-built "class"

我有一个服务,PageService,我这样测试(简化)...

var database = require("../database/database");
var PageService = require("./pageService");

describe("PageService", function () {
    var pageService = {};

    before(function (done) {
        pageService = new PageService(database);
    }

    it("can get all Pages", function (done) {
        pageService.getAll(function (err, pages) {
            if (err) return done(err);

            pages.should.be.instanceOf(Array);
            pages.length.should.be.greaterThan(1);
            done();
    });
});

我一直在努力使用 bluebird 来 promisify 挂起 PageService 的所有方法(getAll、getById、创建、更新、删除等)。我已经查看了关于该主题的多个讨论,但大多数似乎都关注试图让构造函数 return 做出承诺。我只想承诺所有挂在 class 我通过构造函数创建的函数。这是 pageService = new PageService(database);我无法通过承诺。

PageService 仅使用基本的构造函数模式 - 例如

self.getAll = function(next) {
    self.collection.find({}, function(err, docs) {
        if (err) return next(err);

        next(null, docs);
    });
};

如果有人能告诉我正确的方法来轻松地 promisify 从构造函数 returned 对象挂起的所有函数,我将不胜感激。我也对我可能以错误的方式做这件事持开放态度。我对一般的承诺还很陌生,欢迎指导。

更新

我通过执行以下操作得到了承诺的功能...

pageService = new PageService(database);
Promise.promisifyAll(pageService);

... 但是,每次我新建一个服务实例时,通过承诺来 运行 似乎是一种不好的做法。我想要一种只承诺一次的方法。我认识到在服务中手动 returning promises 可能是解决方案,但我希望通过 bluebird magic 获得更优雅的东西。

你不应该担心每次promisification。它所做的只是将您的回调包装在适当的承诺代码中。无需担心性能损失,这是一个完全可以接受的解决方案。

也没有别的办法了。这一切都归结为两个解决方案:使用 Bluebird promisification 或手动重写您的服务以使用 promises.

页面服务模块:

function PageService(collection) {
    this.collection = collection;
}
PageService.prototype.getAll = function(next) {
    this.collection.find({}, function(err, docs) {
        if (err) return next(err);
        next(null, docs);
    });
};

module.exports = PageService;

测试模块

var should = require("should");
var Promise = require("bluebird");
var database = { // mockup
    find: function (options, next) {
        next(null, ['the', 'list', 'of', 'docs']);
    }
};
var PageService = require("./PageService");

Promise.promisifyAll(PageService.prototype);

describe("PageService", function () {
    var pageService;

    before(function () {
        pageService = new PageService(database);
    });

    it("can get all pages", function () {
        return pageService.getAllAsync()
        .then(function (pages) {
            pages.should.be.instanceOf(Array);
            pages.length.should.be.greaterThan(1);
        });
    });
});