最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to use function chaining with async function? - Stack Overflow

programmeradmin0浏览0评论

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?

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?

Share Improve this question edited Mar 29, 2019 at 9:12 Dominik asked Mar 29, 2019 at 8:22 DominikDominik 4371 gold badge4 silver badges18 bronze badges 5
  • I tried this code in a Codepen, and return this; only returns Walker {t: undefined}, with only t and without the two methods goToMainPage and goToProfile. I'm a bit puzzled by this. Why aren't the methods part of the instanciated class? Can someone explain? – Jeremy Thille Commented Mar 29, 2019 at 8:32
  • @jeremy cause they are part of the prototype? Walker { ... } tells you about the inheritance... – Jonas Wilms Commented Mar 29, 2019 at 8:37
  • @JeremyThille it is not code that should work properly, more like sudo code. I updated the example a litte. We would need to pass the t object during the instantiation of the class e.g. new Walker(t). The t es from another library I'm using. You can just think of it as a object which gives you a bunch of asynchronous functionality. – Dominik Commented Mar 29, 2019 at 9:14
  • @JonasWilms so, are methods of a class only part of the prototype and not part of the class itself? That's weird – Jeremy Thille Commented Mar 29, 2019 at 9:18
  • @jeremy Umm... new Walker is still an instance, and thats what this is pointing to. And yes, only static methods are part of the constructor itself, methods are part of the prototype. Remember: class is just syntactic sugar around constructors. – Jonas Wilms Commented Mar 29, 2019 at 9:41
Add a ment  | 

2 Answers 2

Reset to default 7

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!

You're using async/await - it's essentially a replacement for Promise chaining (and Promises are themselves a solve for callback hell). If you really wanted to use chaining:

walker().then(w => w.goToMainPage()).then(w => w.goToProfile());
发布评论

评论列表(0)

  1. 暂无评论