Q
Q
quex2014-02-26 09:18:48
Node.js
quex, 2014-02-26 09:18:48

Event chaining in node.js

Problem 1
I know about the great async module, but it doesn't quite fit the situation, at least I haven't found a way to use it concisely.
The situation is the following. I am writing a parser that receives data through a third-party api, processes it and then saves it in the database in the form I need. Data is received through different interfaces and api methods, glued together, images are downloaded using links from the response, etc.
The parser is inherited from EventEmitter, and at certain stages of its work, emits events accordingly. This was done in order to be able to hang various callbacks, without hardcode. Let's say if we request a list of refrigerators through api, they will have their own characteristics, but if we request TVs - our own. Accordingly, they need to be processed differently.
Question 1: how to correctly emit events, say 'end' (the parser has finished working).
For example, I request a certain list of goods through the api. When a response is received from the api, the 'itemlist' event is emitted, the product list contains urls with links to product photos, which we also need to download, after downloading them, the 'photos' event is emitted. How to emit an 'end' event that occurs after 'itemlist' and 'photos' have happened?
i did it like this:

// <!-- эмит события end
var emitted = {itemlist:false, photos:false};
  
self.once('itemlist', function(){
  emitted.itemlist = true;
  if (emitted.photos){
    process.nextTick(self.emit.bind( self, 'end' ));
  }
});

self.once('photos', function(err, res, txt){			
  emitted.photos = true;
  if (emitted.itemlist){
    process.nextTick(self.emit.bind( self, 'end' ));
  }
});
// -->

works, but for some reason, my gut tells me that this is a crutch. especially what to do if we have not two events, but 5 for example.
Problem 2
Let's say we get a list with product names via api in different languages, say five, i.e. we make 3 requests (3 languages). When receiving a response, emit the 'list' event.
After receiving all the lists, emit the 'lists' event (all lists received).
Here you can use async.parallel
async.parallel([
    function(cb){ getLang(1, function(){self.emit('list');cb();}) },
    function(cb){ getLang(2, function(){self.emit('list');cb();}) },
    function(cb){ getLang(3, function(){self.emit('list');cb();}) },
],function(err){self.emit('lists')});

I hang several handlers on the 'list' event, which extract the necessary data from the list and glue them with a certain common object (which will be stored in the database later).
Question 2: Does such an implementation guarantee that when the 'lists' event occurs, the shared object will already be ready for saving and all list event handlers on each list will already have completed? nextTick is needed in the final callback or not?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
A
Alexander Keith, 2014-02-26
@tenbits

Regarding the first question, I do like this:

var await = new (require("atma-class")).Await;

self.once("itemlist", await.delegate());
self.once("photos", await.delegate());

await
    .done(function() {
        self.emit("end");
    })
    .fail(function(error) {
        self.emit("error", error);
    });

I
Ivan Starkov, 2014-02-28
@icelaba

Take any promise library
for example https://github.com/kriskowal/q
or from the list here wiki.commonjs.org/wiki/Promises/A
then the reduction of data from a heap of sources will look like
q.all([source1, .., sourceN ])
.then(function(results){
})
forgot like a bad dream about async and so on

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question