Take this code, where f
is a stream that has an event 'body', which calls the listeners with a m
-- which is itself a stream emitting events:
f.on('message', function(m) {
m.on('body', function(stream, info) {
var b = '';
stream.on('data', function(d) {
b += d;
});
stream.on('end', function() {
if (/^header/i.test(info.which))
msg.header = Imap.parseHeader(b);
else
msg.body = b;
});
});
m.on('attributes', function(attrs) {
msg.attrs = attrs;
msg.contentType = partID[1];
});
});
f.on('end', function() {
if (hadErr)
return;
cb(undefined, msg);
});
The backend is emitting a 'message' event, passing it a m
object. The code then listens to the events body
and attributes
. It's all straightforward except that my little brain is in a bit of a crisis (I am not used to dealing with streams). Especially: how is the backend emitting from the f
and m
objects, to guarantee that events are indeed called at the right time?
Specifically:
f
have to be coded, in general terms, in order to make sure that m
m doesn't emit till m.on('body', function(stream, info) {
is called?f
and m
will emit events after the code here has registered?b.emit('end')
is called after m.emit('end'), how is that even supposed to happen really, still guaranteeing that on()
is called before
any one of the events are emitted?OK I am 100% confused about this matter. I am obviously missing something basic and crucial, and I am not even able to ask the right questions because of this...! (Apologies)
Does a listener need to be added with on() before the event is emitted in order for it to be caught?
Yes.
If so, does that mean that f and m will emit events after the code here has registered?
No, events are not queued anywhere. If nothing is listening for them, they will be lost. I think that's what you're asking anyway... f
and m
don't seem to emit events in your code.
If the backend is supposed to guarantee that b.emit('end') is called after m.emit('end'), how is that even supposed to happen really, still guaranteeing that on() is called before any one of the events are emitted?
b
is a string in your example? I'm not sure what you're asking here.
Think of it differently. When .on
is called, a function is subscribed to a channel of messages. Those messages are already flowing before that function is subscribed, and will continue to flow if that function is unsubscribed. .on
and .removeListener()
just set the subscription status for a particular function.
Events can be emitted even if nothing is listening for them. Events can fire all the time and if nothing is listening, they just don't go anywhere. (An exception to this are the error events built into Node.js, which are turned into real exceptions if there isn't an error handler.)
How would f have to be coded, in general terms, in order to make sure that mm doesn't emit till m.on('body', function(stream, info) { is called?
I still don't follow specifically what you're asking, since none of the code you show emits anything. But, you wouldn't really want to do this. You need to be setting up your event handlers before opening a stream, or doing whatever you are doing that causes the events to be fired.
You might be getting confused on the ordering of event handling on new objects. In Node.js, there is a rule... Never emit directly from your constructor. Always use nextTick()
or similar. This way, after instantiation, any code to attach itself to event handlers can do so before the events are emitted.
Also, if you are using streams, consider using the readable
event so that the stream remains paused until you're ready to read from it. Pull vs. push.