1

The code could be simplified to something like that,

function start(callback) {
    one.on('ready', () => {
        console.log('one server ready');
    });

    two.on('ready', () => {
        console.log('two connection ready');
    });

    one.connect();
    two.start();
}

I need to call that callback, after both services getting to ready state. What's the best pattern for that?

Update: Ideas how to do that with RxJS are welcome :)

Alexander Beletsky
  • 19,453
  • 9
  • 63
  • 86

5 Answers5

8

You asked for promises, let's see how we can convert one time events to promises, aka promisifying the emitters:

function ready(ee){
    return new Promise(function(resolve) {
        ee.on("ready", resolve); // resolve when ready
    });
}

Which would let you do:

Promise.all([ready(one), ready(two)]).then(function(){
   // both ready here
});

You can easily aggregate promises which is very nice :)

Community
  • 1
  • 1
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
6

The RxJS way of approaching it would be to use either zip or when/and/thenDo for the synchronization, and fromEvent to manage the EventEmitter

function ready(ee) {
  return Rx.Observable.fromEvent(ee, 'ready');
}

//EITHER
var option1 = Rx.Observable.when(ready(one).and(ready(two))
                                 .thenDo((first, second) => "Both Ready!"));

//OR
var option2 = Rx.Observable.zip(ready(one), ready(two), 
                                (first, second) => "Both Ready!");

option1.take(1).subscribe(() => callback());
paulpdaniels
  • 18,395
  • 2
  • 51
  • 55
1

Low-tech

A low-tech way is to maintain a counter of events and then call the callback when you have received enough:

function start (callback) {

    var numSteps = 2;
    var currStep = 0;

    var step = function () {

        currStep++;
        if (currStep === numSteps) {
            callback();
        }
    }

    one.once('ready', () => {

        step();
        console.log('one server ready');
    });

    two.once('ready', () => {

        step();
        console.log('two connection ready');
    });

    one.connect();
    two.start();
}
Matt Harrison
  • 13,381
  • 6
  • 48
  • 66
0

You can look at the event-as-promise package. It convert events into Promise continuously until you are done with all the event processing.

In your case,

import EventAsPromise from 'event-as-promise';

const oneReady = new EventAsPromise();
const twoReady = new EventAsPromise();

one.once('ready', oneReady.eventListener);
two.once('ready', twoReady.eventListener);

await Promise.all([one.upcoming(), two.upcoming()]);

Simple and cleaner than RxJS in this case.

Compulim
  • 1,148
  • 10
  • 18
0

With jQuery ($):

$('#greet').one('click', function(evt){
  $(evt.currentTarget).one('click', function(){
    alert('Hi!');
  });
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<button id="greet">Greet ONLY on second click.</button>

Good Luck...

Aakash
  • 21,375
  • 7
  • 100
  • 81