2

Is it possible to use a Proxy to wrap calls to async methods on an object with error handling?

I tried the code below, but the catch isn't executing when errors are occurring in the proxied method.

const implementation = {
    // proxied async methods here
}
const proxy = new Proxy(implementation, {
    get: (target, prop, reciever) => {
        try {
            return Reflect.get(target, prop, reciever)
        }
        catch (error) {
            console.log('Error:')
            console.error(error)
        }
    }
})

My goal was to avoid implementing error-handling in each proxied method.

derekbaker783
  • 8,109
  • 4
  • 36
  • 50
  • This has nothing to do with proxies. The code doesn't work in a normal function either. You need to use either `await` in your `try` block, or use promise methods like `.then()`/`.catch()`. – Bergi Jul 01 '21 at 19:56
  • 1
    Wait, actually it has to do with proxies as well: you are not actually **wrapping** the *method call* that might throw/reject, the only errors you handle are from getters (from *accessing* the method). – Bergi Jul 01 '21 at 19:58
  • 1
    See https://2ality.com/2015/10/intercepting-method-calls.html, https://stackoverflow.com/questions/50027225/in-the-proxy-handler-how-to-distiguish-getting-a-property-var-vs-calling-a-me https://stackoverflow.com/questions/61494556/is-there-a-way-to-use-javascript-es6-proxy-to-spy-on-object-methods – Bergi Jul 01 '21 at 20:03

1 Answers1

5

I tried an approach inspired by Dr. Axel (suggested by Bergi in the question comments), and it works as desired:

const object = {
  async foo() {
    return new Promise((resolve, reject) => { reject('Boom!') })
  }
}

function interceptMethodCalls(obj) {
  const handler = {
    get(target, propKey, receiver) {
      const origMethod = target[propKey];

      return async function (...args) {
        try {
          return await origMethod.apply(this, args);
        }
        catch (error) {
          console.log('Caught:')
          console.error(error)
        }
      }
    }
  }

  return new Proxy(obj, handler);
}

const proxy = interceptMethodCalls(object);
proxy.foo()

Output of the above script:

Caught:
Boom!
derekbaker783
  • 8,109
  • 4
  • 36
  • 50