链接时输入错误 Q.ninvoke
Type error when chaining Q.ninvoke
当我尝试使用 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
那样正确传递。我已经在 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本身有bug?
我使用的包版本:
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')
时集合本身尚未创建。在您的 correct/working 版本中,这将得到解决,因为 ninvoke
绑定在创建集合之后才会发生。我现在看到一般问题是你如何调用 .ninvoke() 超过它在链中的初始使用。
您更新的示例没有直接帮助,因为您使用的是 ninvoke()
但没有使用节点样式的回调形式,所以您一定会遇到不同类型的错误。
至少参考您的新非Mongo 示例,根本问题是您在后续调用中如何使用.ninvoke()
。在初始 Q.ninvoke()
之后的后续 .ninvoke()
调用应用于 returned 承诺时,使用承诺的 return 值作为第一个参数。这可能比其他任何东西都更容易说明,请查看我对您的 "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 集合,所以你可能修改您之前的代码:
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 :-)
但是,我不确定您想要对 "close" 做什么,因为 createIndex 可能不只是 return 对数据库的引用。我不知道 API 但大概你可以使用 Q 的 .get()
or related functions 来找到它然后传递给 .ninvoke('close')
.
有关 Q 中实现的讨论,请参阅 this issue,其中还有 link 对实现它所做的更改,您可以确切地看到它是如何工作的。
当我尝试使用 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
那样正确传递。我已经在 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本身有bug?
我使用的包版本: 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')
时集合本身尚未创建。在您的 correct/working 版本中,这将得到解决,因为 ninvoke
绑定在创建集合之后才会发生。我现在看到一般问题是你如何调用 .ninvoke() 超过它在链中的初始使用。
您更新的示例没有直接帮助,因为您使用的是 ninvoke()
但没有使用节点样式的回调形式,所以您一定会遇到不同类型的错误。
至少参考您的新非Mongo 示例,根本问题是您在后续调用中如何使用.ninvoke()
。在初始 Q.ninvoke()
之后的后续 .ninvoke()
调用应用于 returned 承诺时,使用承诺的 return 值作为第一个参数。这可能比其他任何东西都更容易说明,请查看我对您的 "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 集合,所以你可能修改您之前的代码:
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 :-)
但是,我不确定您想要对 "close" 做什么,因为 createIndex 可能不只是 return 对数据库的引用。我不知道 API 但大概你可以使用 Q 的 .get()
or related functions 来找到它然后传递给 .ninvoke('close')
.
有关 Q 中实现的讨论,请参阅 this issue,其中还有 link 对实现它所做的更改,您可以确切地看到它是如何工作的。