Ameet Gohil
Ameet Gohil

Reputation: 93

How to create an async function that waits on an event in Javascript?

How do I block on the event?

const EventEmitter = require('events').EventEmitter;
const util = require('util');

function Task() {
    EventEmitter.call(this);
    this.setMaxListeners(Infinity);

    this.dosomething = () => {
    console.log("do something");
    };

    this.run = (iter) => {
    for(i = 0; i < iter; i++) {
            this.dosomething();
        this.emit('someevent');
    }
    }

}

util.inherits(Task, EventEmitter);

task = new Task();

function do_work() {
    console.log("work 1");
    task.once('someevent', (props) => {
    console.log('event happened');
    });
    console.log("work 2");
}

do_work();
task.run(5);

Acutal Result
work 1
work 2
do something
event happened
do something
do something
do something
do something

Expected Result
work 1
do something
event happened
work 2
do something
do something
do something
do something

Upvotes: 3

Views: 1943

Answers (1)

Dacre Denny
Dacre Denny

Reputation: 30360

If I understand your question correctly, then this can be achieved via a Promise that wraps the task event handler:

async function do_work() {

  console.log("work 1");

  // use a promise to block completion of do_work() function
  // until task event callback has been invoked
  await (new Promise(resolve => {

    task.once('someevent', (props) => {

      console.log('event happened');

      // Now that task callback has been invoked, "resolve" the
      // enclosing promise to allow do_work()'s execution to complete
      resolve();

    });
  }));

  console.log("work 2");
}

The idea in the code above is to wrap the task someevent handler so that the promise resolve can be invoked once the event handler has fired (ie by calling resolve()). This allows the call to do_work() to resume, to achieve the desired execution behavior.

Also, you will need to do something like this:

// Because do_work() is async, and becase you want to ensure that
// do_work() completes before starting task.run(5), you need to enclose
// these in an async function, eg doWorkThenRunTasks()
async function doWorkThenRunTasks() {

  // Call do_work asynchronously
  await do_work()

  // task.run will happen after do_work completed
  task.run(5);
}

doWorkThenRunTasks();

The addition of the async doWorkThenRunTasks() function allows you to use await in relation to do_work() to enforce execution order of task.run(5) after completion of do_work().

Hope this helps!

Upvotes: 3

Related Questions