Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

199
Views
abstract base class with async methods that can sometimes be sync

tl;dr - how to make a version of a class that has all its async methods replace by sync ones? (or visa versa)

Background info:

I have created an abstract base class using symbols, something like this:

  const sProtectedMethod = Symbol();
  class AbstractBase() {
    constructor() {
      if (new.target === AbstractBase) {
        throw new TypeError(`AbstractBase is abstract and cannot be instantiated directly. Use a derived class`);
      }
    }
    async #protectedMethod() { // this is just a convience to avoid the ugly symbol syntax everytime we call the function
      await this[sProtectedMethod]();
    }
    async publicMethod() {
      await longAndComplexFunctionCallChainThatEventuallyAwaitsProtectedMethodButDoesntAwaitAnythingElse();

  }

where the derived classes look like this:

  class Derived extends AbstractBase {
    async [sProtectedMethod]() {
      // implementation here
    }

So far so good. But - in some derived classes the implementation of the overriden method must be async (because it does I/O or whatever) while in other implementations this method could be synchronus. I did an experiment to see if making the method synchronus would be faster and it is - approx. 1000x faster.

I could make 2 versions of the AbstractBase - a sync and an async version. But here's the catch - the protectedMethod is actually called many times, pretty deep into a long chain of functions - all of which must be async if the overriden implementation is also async.

So rather than maintain 2 versions of the class that are almost identical, I'd like a way to automatically create a sync version from an async version, or visa versa.

I have managed this with a string replace and an eval

const AbstractBaseSync = eval(`${AbstractBase.toString().replace(/async|await/g, ``)}; AbstractBase`);

But even though I think this is safe (providing there are no strings within the class that contain the words async or await), the use of eval and I'm hoping there is a better way.

Also, although it seems to work in Chrome, Firefox + Node - I know implementations of toString may differ, which might cause issues later.

If I dispensed with the #private members and used _convention instead, then maybe I could do it member by member with reflection, but I don't think it would be much better as eval or new Function(...) would still be required.

What is the cleanest way to do this?

about 4 years ago · Juan Pablo Isaza
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!