0

I got a sensor class and a class which extends it. The constructors of both classes use async operations.

Base class:

/**
 * Basic sensor class
 */
class Sensor {
  /**
   * Constructor function
   * @param {object} options - sensor options
   * @param {*} callback - fn(err)
   */
  constructor(options, callback) {
    ...
    callback(null);

Version A (fails): Extended class, calling this in super's callback:

ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor

/**
 * Mock of the Chirp water level sensor.
 */
class ChirpSensorMock extends SensorMock {
  /**
   * Constructor function
   * @param {object} options - sensor options
   * @param {*} callback - fn(err)
   */
  constructor(options, callback) {
    super(options, (err) => {
      if (err) { return callback(err); }
      async.eachSeries(this.detectors,

Version B (works, but gives eslint error):

Missed superclass's construction invocation

  constructor(options, callback) {
    async.series([
      (next) => super(options, next),
      (next) => {
        async.eachSeries(this.detectors,

Is there a way with using callbacks (and avoiding async/await) to call super and use this in the callback? Or should I just ignore the eslint error, e.g. with // eslint-disable-next-line constructor-super

Andi Giga
  • 3,744
  • 9
  • 38
  • 68
  • 2
    "The constructors of both classes use async operations." this is an antipattern. You could say implement some `init` method to be called after instance is created or a factory method that does async stuff before creating instance. – Yury Tarabanko Jul 18 '19 at 10:14
  • You would need to make sure that the callback is always called asynchronously, when the instance is already initialised. But as Yury said, the actual problem is [doing asynchronous things in a constructor](https://stackoverflow.com/q/24398699/1048572) (or even taking a callback). – Bergi Jul 18 '19 at 10:30
  • @Bergi I understand the discussion in the link. I'm still not sure how it makes sense in my case. The sensor needs to be booted async. I already have that async boot in a class method. I could call boot after `new` but then my sensor is still not usable till then. Separating the boot fn does also not make much sense imho because it utilizes methods of the class. – Andi Giga Jul 19 '19 at 08:35
  • @AndiGiga how can it utilise methods of the class while the instance is not yet usable? If you consider those to be "internal methods" that don't have to do anything with whether an instance is "externally usable", maybe you should split up the implementation. Otherwise, yes, calling `await instance.boot()` after creating the instance, before using it, is a reasonable solution. (Much more than doing the async stuff inside the constructor). – Bergi Jul 19 '19 at 08:42

1 Answers1

1

You can try binding this in Sensor to your callback which will be the this value of callback(Will not work in arrow function) of any class that extends Sensor

    class Sensor {
  /**
   * Constructor function
   * @param {object} options - sensor options
   * @param {*} callback - fn(err)
   */
  constructor(options, callback) {
    ...
    callback.call(this,null);
  }
}

class ExtendSensor extends Sensor{
  constructor(){
    super(option, function(v){
    console.log(v, this) //v == null, this == ExtendSensor{}
    });
  }
}
Ndifreke
  • 732
  • 1
  • 8
  • 13