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?
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With