node.js - 链接 Q.ninvoke 时出现类型错误

标签 node.js mongodb q

当我尝试使用 Q 链接 Node.js 中的 mongodb 函数时出现错误,如下所示:

Q.ninvoke(MongoClient, 'connect', 'mongodb://127.0.0.1:27017/mydb')
.then(function(db){
    return Q
    .ninvoke(db, 'createCollection', 'mycollection')
    .ninvoke(db.collection('mycollection'), 'createIndex', {id: 1}) // error occurs here
    .ninvoke(db, 'close')
    .then(function(){...})
});

我收到的错误消息:

TypeError: Cannot call method 'apply' of undefined
  at Promise.post (/path/to/my/project/node_modules/q/q.js:1157:36)
  at Promise.promise.promiseDispatch (/path/to/my/project/node_modules/q/q.js:784:41)
  at /path/to/my/project/node_modules/q/q.js:600:44
  at runSingle (/path/to/my/project/node_modules/q/q.js:133:13)
  at flush (/path/to/my/project/node_modules/q/q.js:121:13)
  at process._tickCallback (node.js:442:13)

根据消息,q.js 中的第 1157 行内容是:

Q.fulfill = fulfill;
function fulfill(value) {
    return Promise({
    ...
    "post": function (name, args) {
        if (name === null || name === void 0) {
            return value.apply(void 0, args);
        } else {
            return value[name].apply(value, args); // error occurs here: line 1157
        }
    }

虽然我不太清楚 Q 内部发生了什么,但我猜想 db.collection('mycollection') 没有作为第 1157 行中的 value 正确传递。I'我们在 Github of q 上提出了这个问题但还没有得到任何回复。

如果我像这样更改代码,一切都会再次正常工作:

Q.ninvoke(MongoClient, 'connect', 'mongodb://127.0.0.1:27017/mydb')
.then(function(db){
    return Q
    .ninvoke(db, 'createCollection', 'mycollection')
    .then(function(){
        return Q.ninvoke(db.collection('mycollection'), 'createIndex', {id: 1}) // no error this time
        .then(function(){
             return Q.ninvoke(db, 'close').then(function(){...});
        });
    });
});

然而,这里出现了一座随着链条一起生长的金字塔。我认为 Q 应该像第一个示例一样支持链接 ninvoke

简而言之,我的问题是Q的使用是否存在误解,或者Q实际上存在错误?

我使用的软件包版本: Node .js:v0.10.36 问:1.4.0 mongodb:2.0.31

更新

我排除了MongoDB的因素,将问题范围缩小如下:

var TestClass = function (name){
};

TestClass.prototype.printName = function (callback) {
    console.log('printName called');
    return callback(null);
};

var test = new TestClass('test object');

test.printName(function (err) {
    test.printName(function (err) {
        console.log('callback called');
    });
});

在这种情况下,输出应该是:

$ node q-test.js
printName called
printName called
callback called

但是如果我按如下方式使用 Q:

Q.ninvoke(test, 'printName')
.ninvoke(test, 'printName')
.then(function(){
    console.log('callback called');
})
.done();

结果输出有这样的错误:

$ node test.js
printName called

/path/to/my/project/node_modules/q/q.js:155
                throw e;
                      ^
TypeError: Cannot read property '[object Object]' of undefined
    at Promise.post (/path/to/my/project/node_modules/q/q.js:1161:29)
    at Promise.promise.promiseDispatch (/path/to/my/project/node_modules/q/q.js:788:41)
    at /path/to/my/project/node_modules/q/q.js:556:49
    at runSingle (/path/to/my/project/node_modules/q/q.js:137:13)
    at flush (/path/to/my/project/node_modules/q/q.js:125:13)
    at process._tickCallback (node.js:442:13)
    at Function.Module.runMain (module.js:499:11)
    at startup (node.js:119:16)
    at node.js:929:3

最佳答案

TL;DR 版本:在链中调用时,而不是直接调用 Q.ninvoke()要调用其函数的对象来自链中先前函数的结果,而不是来自 qpromise.ninvoke() 的第一个参数打电话。

详细说明: 虽然我最初快速浏览了一下,认为问题在于您的原始代码中,当 db.collection('mycollection') 时,集合本身尚未创建。在下面的行中被调用。在您的正确/工作版本中,这将得到解决,因为 ninvoke在创建集合之后才会发生绑定(bind)。我现在发现一般问题是如何在链中首次使用 .ninvoke() 后调用它。

您更新的示例没有直接帮助,因为您正在使用 ninvoke()但没有使用 Node 样式的回调形式,因此您必然会遇到不同类型的错误。

至少引用您的新非 Mongo 示例,根本问题是您如何使用 .ninvoke()在您随后的通话中。初始后Q.ninvoke()后续.ninvoke()当应用于返回的 Promise 时,调用使用 Promise 的返回值作为第一个参数。这可能比其他任何事情都更容易说明,请查看我对“printName”示例所做的更改:

var TestClass = function (name){ };

TestClass.prototype.printName = function (callback) {
    console.log('printName called');
    return callback(null,this);     // node style callback, also return this
};

var test = new TestClass('test object');

Q.ninvoke(test, 'printName')
//  in the lines below, the result of the prior line is the "implied" first
// parameter to ninvoke();
.ninvoke('printName')
.ninvoke('printName')   
.then(function(){
    console.log('callback called');
})
.done();

希望这能说明正在发生的事情。

回到你原来的问题,虽然我不是 Mongo 用户,但从查看文档来看, createCollection 实际上返回了集合,因此你可以修改你之前的代码:

return Q
.ninvoke(db, 'createCollection', 'mycollection')
.ninvoke(db.collection('mycollection'), 'createIndex', {id: 1}) // error occurs here

进入

return Q
.ninvoke(db, 'createCollection', 'mycollection')
.ninvoke('createIndex', {id: 1}) // error *should not occur* here :-)

但是,我不确定您想要对“关闭”执行什么操作,因为 createIndex 可能不仅仅返回对数据库的引用。我不知道 API,但想必你可以使用 Q 的 .get() or related functions到达它,然后传递到 .ninvoke('close') .

参见this issue有关 Q 中实现的讨论,其中还包含实现它所做的更改的链接,您可以准确地了解它是如何工作的。

关于node.js - 链接 Q.ninvoke 时出现类型错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30181026/

相关文章:

javascript - 将 jQuery .each 中具有多个 .get() 的函数转换为 q Promise

node.js - Promise with q 框架和 Node.js 中的回调模式?

javascript - Mongoose 模型 key 未插入 Postman 发布请求中

node.js - 设置 node.js 数据库 MongoDB/Redis 的最佳方式?

node.js - 如何将 Google actions 对话框流与 hapi Node js 框架集成?

MongoDB AuthenticationFailed 机制 MONGODB-CR

javascript - 使用 mongoose 插入 MongoDB 时在键中使用 "@"

独立脚本中的 javascript node.js,阻止/等待 promise

javascript - 如何为我的 React 应用程序解决 "Element type is invalid"?

node.js - 我的 Karma 配置跳过了 Jasmine 单元测试