Reputation: 1820
I am new to the continuation passing style of asynchronous computation used in Node.js applications, and I'm struggling to get a grip on some fairly basic code.
I am trying to write a library which will create an imap interface to imap.gmail.com, and I am trying to follow BDD with 'vows'.js' (with varying levels of success. I'm definitely not following the full red->code->green cycle that I should be, but it's hard to get started in a language that way).
The relevant test case looks like this:
var gmail = require('../lib/gmail.js'),
vows = require('vows'),
assert = require('assert'),
fs = require('fs');
vows.describe('Basic interface tests').addBatch({
'A GMailInterface object can': {
topic: function() {
var gm = Object.create(gmail.GMailInterface);
var settings_file = 'test/test_settings.json';
var settings = JSON.parse(fs.readFileSync(settings_file));
var that = this;
gm.connect(settings.email,settings.password,function() {
that.callback(gm); // ERROR BEING GENERATED HERE
});
},
// ACTUAL VOWS OMITTED - the following is just a test of the callback
'find an email' : {
topic: function(gm) {
console.log(">>>",gm);
},
}
}
}).export(module)
If I write a console.log message right above the line with "ERROR BEING GENERATED HERE", it will print. It will not if I put a message below it. The output of the test gives the following error:
node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: Uncaught, unspecified 'error' event.
at EventEmitter.<anonymous> (events.js:50:15)
at EventEmitter.emit (/Users/eblume/Repositories/my_stuff/gmail/node_modules/vows/lib/vows.js:236:24)
at /Users/eblume/Repositories/my_stuff/gmail/node_modules/vows/lib/vows/context.js:31:52
at Object.callback (/Users/eblume/Repositories/my_stuff/gmail/node_modules/vows/lib/vows/context.js:46:29)
at Array.0 (/Users/eblume/Repositories/my_stuff/gmail/test/gmail_test.js:17:14)
at EventEmitter._tickCallback (node.js:192:40)
The code in gmail.js is a bit too much to post here, but here is what I think is the relevant section - I can post more if you ask a question below.
gm.connect = function(username,password,cb) {
var self = this;
self.conn = new ImapConnection({
username: username,
password: password,
host: 'imap.gmail.com',
port: 993,
secure: true
});
async.series([
function(callback){self.conn.connect(callback); },
function(callback){self.conn.openBox('[Gmail]/All Mail',true,callback);}
],
function(err,results) {
if (err) {
die(err);
}
process.nextTick(cb);
});
};
Where might I be going wrong? Thanks for any help!
Upvotes: 0
Views: 768
Reputation: 4635
I recommend reading up on how 'this' works. If nobody's been messing with it the 'that' of that.callback
refers to the parent object which is labeled with a literal string as 'A GMailInterface object can' .
I suspect it's the this factor tripping you up. 'callback' should be defined as a method of the same object as the 'topic' method the way you have things set up and that doesn't strike me as the way it's meant to work.
'this' typically refers to nearest ancestor/parent object by default. It ignores wrapping functions unless they're used as constructors using the 'new' keyword in which case it indicates the object instance. In the case of event callbacks in the DOM (browser JS - not node.js which I don't know in-depth as far as events), it typically refers to the object that's had an event triggered on it.
There's no real kludge being fixed with that and self. We just tend to use those to be certain we're addressing the top object in cases where an object has aggregate objects.
Upvotes: 1