Search code examples
node.jseventemitternode.js-stream

Execute when both(!) events fire .on('end')


I have a node app that reads two files as streams. I use event.on('end') to then work with the results. The problem is I don't really know how I can wait for BOTH events to trigger 'end'.

What I have now is:

    reader1.on('end', function(){
        reader2.on('end',function(){ 
          doSomething();
        });
    }); 

With small files this works, but if one of the files is very large the app aborts.


Solution

  • Your execution logic is somewhat flawed. You ought to do something like this instead

    var checklist = [];
     // checklist will contain sort of a counter
    function reader_end(){
        if(checklist.length == 2 )
         // doSomething only if both have been added to the checklist
            doSomething();
    }
    reader1.on('end', function() {
        checklist.push('reader1');
        // increment the counter
        reader_end();
    });
    reader2.on('end', function() {
        checklist.push('reader2');
        reader_end();
    });
    

    Although there are libraries to better handle this sort of stuff, like Async and Promises.


    With Async you'll need to use compose

    var r12_done = async.compose(reader1.on, reader2.on);
    r12_done('end', function(){
        doSomething();
    });
    

    Edit: I just noticed that since probably reader1.on is a Stream 'end' event which doesn't have the standard callback argument signature of (err, results), this probably won't work. In that case you should just go with Promise.


    With Promise you'll need to first Promisify and then join

    var reader1Promise = Promise.promisify(reader1.on)('end');
    var reader2Promise = Promise.promisify(reader2.on)('end');
    
    var reader12Promise = Promise.join(reader1Promise, reader1Promise);
    
    reader12Promise.then(function(){
        doSomething();
    });