链接Q.ninvoke时键入错误

时间:2015-05-12 03:01:53

标签: 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。我已经在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(){...}); }); }); }); 上提出了这个问题。 {3}}但是没有得到任何回应。

如果我改变这样的代码,一切都可以正常工作:

ninvoke

然而,这里出现了一个与链条一起成长的金字塔。我认为Q应该像第一个例子一样支持链接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'); }); });

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

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

更新

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

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

在这种情况下,输出应为:

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

但如果我使用Q如下:

$ 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

结果输出有这样的错误:

word

1 个答案:

答案 0 :(得分:2)

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

<强>精化: 虽然我最初想一想,问题在于您的原始代码,但在以下行调用db.collection('mycollection')时,尚未创建集合本身。在正确/正常的版本中,这将得到解决,因为ninvoke绑定直到创建集合后才会发生。我现在看到一般问题是你如何调用.ninvoke()超过它在链中的初始使用。

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

至少提到您的新非Mongo示例,根本问题是您在后续调用中使用.ninvoke()的方式。在应用于返回的promise的初始Q.ninvoke()后续.ninvoke()调用之后,使用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')

有关Q中实现的讨论,请参阅this issue,其中还包含指向实现它的更改的链接,您可以确切了解它是如何工作的。