1

I have made a class Service. I am trying to run a Interval every X seconds. The default is 30 seconds. But I want to set a custom delay if needed in other classes. I can't find a way to override the variables in my parent class.

class Service {
    
    delay = 30;

    constructor(api, client = undefined) {
        this.api = api;
        this.client = client;
        this.handle();
    }

    getMiliSeconds() {
        return this.delay * 1000;
    }

    service = async () => {
        // Service to run in background
    }

    handle() {
        setInterval(() => { this.service() }, this.getMiliSeconds());
    }
}

module.exports = Service;

When I extend the class Service I am trying to override the delay variable

class Notification extends Service {

    delay = 60;

    service = async () => {
        // I am not running every 60 seconds.
    }
}

module.exports.Notification = Notification;

However the Interval function is still runned every 30 seconds. Instead of the 60 seconds I set in the Notifications class.

2
  • Sure, in my main file I instantiate them like this: let services = [new Notification(api, client), new Receiver(api, client)]; Commented Apr 11, 2021 at 15:36
  • Read this article javascript.info/… Commented Sep 29, 2023 at 7:56

1 Answer 1

8

The problem is that super constructors run before child constructors run or assign to instances. For example:

class Parent {
  prop = 'foo'
  constructor() {
    console.log(this.prop);
  }
}
class Child extends Parent {
  prop = 'bar'
}

will always log foo, because the class field prop = 'bar' will only run after the parent constructor finishes and control flow is yielded back to the child.

When you call this.handle in the super constructor, getMiliSeconds runs immediately, retrieving the delay before the child has had a chance to assign its own delay to the instance.

To fix it, I'd move this.handle out of the constructor, so that it can be called on demand after the object is fully instantiated, not before.

In the snippet below, the delay = 1 in the child class is now successfully causing the child service to run every second, instead of every 3 seconds.

class Service {    
    delay = 3;
    constructor(api, client = undefined) {
        this.api = api;
        this.client = client;
    }
    getMiliSeconds() {
        return this.delay * 1000;
    }
    service = async () => {
        console.log('parent service');
        // Service to run in background
    }
    handle() {
        setInterval(() => { this.service() }, this.getMiliSeconds());
    }
}

class Notification extends Service {
    delay = 1;
    service = async () => {
        console.log('child service');
    }
}


const n = new Notification();
n.handle();

Another approach would be to put the delay property on the prototype, instead of as a class field (which is equivalent to inside the constructor - and the time that the relative constructors are permitted to run is the problem):

class Service {    
    constructor(api, client = undefined) {
        this.api = api;
        this.client = client;
        this.handle();
    }
    getMiliSeconds() {
        return this.delay * 1000;
    }
    service = async () => {
        console.log('parent service');
        // Service to run in background
    }
    handle() {
        setInterval(() => { this.service() }, this.getMiliSeconds());
    }
}
Service.prototype.delay = 3;

class Notification extends Service {
    service = async () => {
        console.log('child service');
    }
}
Notification.prototype.delay = 1;


const n = new Notification();

Sign up to request clarification or add additional context in comments.

2 Comments

I didn't realized that but it makes perfectly sense. Thank you! Would it be possible to override the constructor and change the delay there and then call the super() method to call the parents constructor?
No, I don't think so, not in any good way. Child classes just can't interact with the instance at all before the parent's super has finished.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.