Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use function chaining with async function?

I'm currently writing an e2e test and I would like to create some classes which abstract certain async tasks for me. In the end I would like to instantiate an object, which let's me chain async functions. Let's say I have a Walker which let's me navigate through the page. I would like to use it in this way:

const walker = new Walker(t)

await walker
  .goToMainPage()
  .goToProfile()

Currently I can only use it like this:

const walker = new Walker(t)

await walker.goToMainPage()
await walker.goToProfile()

This is a rough implementation of how I currently implemented my Walker Class. Where t is and object which allows me to do asynchronous actions within my browser.

class Walker {
  constructor(t) {
    this.t = t;
  }
  async goToMainPage () {
    await t.goTo('url/main')
    return this
  }
  async goToProfile () {
    await t.goTo('url/Profile')
    return this
  }
}

Any ideas on how to create async chainable function calls?

like image 920
Dominik Avatar asked Oct 22 '25 15:10

Dominik


1 Answers

await does not only work on Promises, but on every object that provides a .then handler ... therefore your Walker could implement a .then method to allow awaiting:

 class Walker {
   constructor(t) {
     this.t = t;
     // set up a task queue for chaining
     this.task = Promise.resolve();
    }

    // shedules a callback into the task queue
    doTask(cb) {
       // TODO: error handling
       return this.task = this.task.then(cb);
    }

    // allows to use this like a promise, e.g. "await walker";
    then(cb) { cb(this.task); }

    goToMainPage () {
      this.doTask(async () => { // shedule to chain
        await t.goTo('url/main')
      });
      return this; // return walker for chaining
   }

 }

That allows you to do:

 await walker.goToMainPage();
 await walker.goToMainPage().goToMainPage();

If you return something from inside doTask, awaiting it will resolve to that:

 returnStuff() {
   this.doTask(() => "stuff");
   return this;
 }

 //...
 console.log(await walker.returnStuff()); // "stuff"
 console.log(await walker.returnStuff().goToMainPage()); // undefined, result gets lost

Have fun with it!

like image 82
Jonas Wilms Avatar answered Oct 24 '25 05:10

Jonas Wilms