Javascript: Throw in async chained methods

async/await javascript
async/await error handling
async/await vs promises
async arrow function
nodejs async/await
async class method javascript
javascript promise
async/await fetch

I've got a class that returns several methods to be chained like this:

class MyClass{
  foo(){
    if(condition) return this;
    else throw;
  }

  bar(){
    if(condition) return this;
    else throw;
  }
}

Conditions are certain checks that may be true or false depending on the internal state of the class

The idea is that I can execute several methods like this:

myInstance.foo().bar();

This way, if any of the conditions in any method fails, this statement will throw an error.

However, now I'm trying to check conditions that require a promise to be resolved:

class MyClass2{
  asynCheck(){
     myPromise.then((condition)=>{
        ... // returning a promise won't work
     });

I want to maintain the same syntax as before (adding an await/then), I don't mind changing foo and bar to be async as well, as long as the following syntax is valid:

await myInstance.foo().asyncCheck().bar();

Is there a way of doing this? Note that there may be more than one asyncCheck and may be called in any order

You can maybe do it with some major hacks...

class MyClass {
  foo() {
    const ret = new Promise((resolve, reject) => {
      resolve(1);
    })
    ret.bar = this.bar.bind(this);
    return ret;
  }

  bar() {
    const ret = new Promise((resolve, reject) => {
      resolve(2);
    })
    // hack `ret` to copy the methods over...
    return ret;
  }
}

(async() => {
  const c = new MyClass;
  console.log(await c.foo())
  console.log(await c.foo().bar())

})()

Simplifying Asynchronous Coding with Async Functions, As of version 7.6, Node.js also ships with async/await enabled by This is how you would chain asynchronous operations using Rejected promises can be handled with the second function passed to then or with the catch method. function doAsyncOp() { // the next line will kill execution throw new  You either have to add a promise rejection handler and not throw an exception or return a rejected promise there - or run that function in another async function that handles the exception instead of rethrowing the same or new exception. To sum it up: Every async function returns a promise. Every promise needs to have a rejection handler.

You could achieve this using an internal Promise field and reassigning it each time you call a method:

class MyClass {
  constructor(promise) {
    if (!promise) this.promise = Promise.resolve();
    else this.promise = promise;
  }
  foo(condition) {
    this.promise = this.promise.then(() => {
        console.log("foo");
        if (!condition) throw 'foo error';
    });
    return this;
  }
  bar(condition) {
    this.promise = this.promise.then(() => {
        console.log("bar");
        if (!condition) throw 'bar error';
    });
    return this;
  }
  asynCheck(conditionPromise) {
    this.promise = this.promise.then(() => {
        return conditionPromise.then(condition => {
          console.log("asynCheck");
          if (!condition) throw 'asynCheck error';
        });
    });
    return this;
  }
  catch(callback) {
    this.promise.catch(callback);
  }
}

let instance = new MyClass();

instance.foo(true)
        .asynCheck(new Promise((res, rej) => setTimeout(() => res(true), 2000)))
        .bar(true)
        .asynCheck(new Promise((res, rej) => setTimeout(() => res(false), 3000)))
        .foo(false)
        .catch(e => console.log(e));

Error handling with Async/Await in JS, Learn error handling in JS with sync and async code and some caveats. We chain the thisThrows() function call with a .catch() call. thisThrows() is an async method; We throw an error in thisThrows(); As thisThrows() is  While the async function is paused, the calling function continues running (having received the implicit Promise returned by the async function). The purpose of async / await is to simplify using promises synchronously, and to perform some behavior on a group of Promises .

After a lot of testing, I found a possible solution extending the class with Promise, ending up with something like this:

class MyClass extends Promise {
  constructor(executor){
    super((resolve, reject)=>{return executor(resolve,reject)});
  }
  foo(){
    return new MyClass((resolve, reject)=>{
      this.then(()=>{
        if(condition) resolve();
        else reject();
      }).catch(()=> reject());
    })
  }

  asyncCheck(){
    return new MyClass((resolve, reject)=>{
      this.then(()=>{
         asyncCondition.then((condition)=>{
             if(condition) resolve();
             else reject();
         });
      }).catch(()=> reject());
    })
  }
}
const bar=new MyClass((r)=>{r()});
await bar.foo().asyncCheck();

The main tradeoff is that the constructor requires a dummy callback due to how extending promises work.

javascript await on multiple chained async functions, This is because getB is an async function and does not return a B object but a Promise object that have no action method. This promise will  What's the right way to make an API in TypeScript that will allow me to chain methods that return promises and then wait for the result with a single await? EDIT: To clarify, this is more of an API design question. Is there a better pattern for doing what I'm trying to do (call an async method on an object returned by an async method)?

Promise-based functions should not throw exceptions, [2016-03-25] dev, javascript, esnext, async, promises You can also start a chain of then() method calls via Promise.resolve() and execute the synchronous  This answer by Tamas Hegedus with parentheses around the await expressions is definitely the way to go with vanilla JavaScript. Alternatively, if you're looking for commonly chained JS methods and don't mind a third-party module you can use async-af on npm. With that you can chain asynchronous methods like so:

Better error handling with async/await - DEV Community ‍ ‍ , Without the .catch block Javascript will throw Unhandled promise rejection We can call a .catch method on the async requests to handle errors. Handling error with .catch in promise .then chain can be difficult unless you  To declare an async class method, just prepend it with async: class Waiter { async wait() { return await Promise.resolve(1); } } new Waiter() .wait() .then(alert); // 1 The meaning is the same: it ensures that the returned value is a promise and enables await .

Deeply Understanding JavaScript Async and Await with Examples, Here's an example of reading a file in Node.js (asynchronously) — fs. Now, instead of nesting callbacks inward, we can chain them. Async functions can also be put on an object as methods, or in class declarations as follows. // As an What happens when you throw an error inside an async function? The throw statement throws a user-defined exception. Execution of the current function will stop (the statements after throw won't be executed), and control will be passed to the first catch block in the call stack. If no catch block exists among caller functions, the program will terminate.

Comments
  • What's the problem? If foo and bar remain synchronous, and only last method of the chain is [possibly] async, it will work fine. Even if the last method is synchronous, await won't choke on it.
  • asyncCheck may be in the middle, and there are more than one async method. I'll edit that to clarify
  • It will have to be function that takes promise... or else you would have to catch before every check
  • Or you Ming miss understood how promises work. Try returning promise inside of promise, you’ll see that it will chain seemlesly
  • It won't chain, @Akxe , in the last example if a promise is returned in asyncCheck, it will try to execute the method bar of the promise returned, which won't exists
  • If you do this then c.foo().bar() will call bar before the Promise return by c.foo() is resolved. I don't think that is what the OP wants. You could adjust the hack to make it work though. Something like ret.bar = async (...args) => { await ret; return this.bar.apply( args ); }
  • @Paulpro Good point. I don't think it's doable then (without more awaits like you sugggested)
  • I think you can adjust the hack in your answer. I edited my above comment, but haven't thought it through too well.
  • I'm trying a hack that it is a bit like yours but the other way around, trying to extend MyClass with Promise
  • Could this work somehow with an async/await statement instead of a catch at the end?
  • @angrykoala you can try, for example, await instance.foo(true).bar(false).promise