# clearInterval() not working

**URL:** <https://discourse.nodered.org/t/clearinterval-not-working/91169>\
**Category:** Developing Nodes\
**Created:** [21 September 2024 19:30 UTC](https://discourse.nodered.org/t/clearinterval-not-working/91169 "2024-09-21T19:30:07Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![wangenkuesse](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/wangenkuesse/32/93551_2.png) [@wangenkuesse](https://discourse.nodered.org/u/wangenkuesse)\
**Post date:** [21 September 2024 19:30 UTC](https://discourse.nodered.org/t/clearinterval-not-working/91169/1 "2024-09-21T19:30:07Z")

</div>

Hello everyone...

I am working on a project with a countdown/timer. I call a function every second via setInterval(). When I edit the node in the editor an deploy, cleaInterval() is not stopping the function. The function is called two times per second. One Instance is out of context.

The log outputs no error when restarting flows

What do I do wrong? Any ideas?

The code around setInterval() and clearInterval()

```auto
        // run ticker every second
        var tick = setInterval(ticker, 1000, node.status);
 
        // kill the ticker
        node.on("close", function () {
            if (tick) { clearIntervall(tick); }
        });

```

Edit:  
clearInterval() without the second german "l" didn't solve the problem.

```auto
        node.on("close", function () {
            if (tick) { clearInterval(tick); }
        });

```

the same: two ticks per second.

The whole js-file...

```auto
module.exports = function (RED) {
    function UIMainswitchNode (config) {
        RED.nodes.createNode(this, config);

        // which group are we rendering this widget
        const group = RED.nodes.getNode(config.group);
        const base = group.getBase();

        // states
        const TIMER_UNDEF = null;
        const TIMER_ON = true;
        const TIMER_OFF = false;

        const INPUT_UNDEF = null;
        const INPUT_ON = true;
        const INPUT_OFF = false;

        const AUTO_UNDEF = null;
        const AUTO_ON = true;
        const AUTO_OFF = false;

        const OUT_ON = true;
        const OUT_OFF = false;

        const TIMER_RUNNING = true;
        const TIMER_NOT_RUNNING = false;

        // Parser for boolean Input
        const BOOL_INPUT_PARSER = {
            true: INPUT_ON,
            false: INPUT_OFF,
            'true': INPUT_ON,
            'false': INPUT_OFF,
            'TRUE': INPUT_ON,
            'FALSE': INPUT_OFF,
            0: INPUT_OFF,
            1: INPUT_ON,
            'On': INPUT_ON,
            'Off': INPUT_OFF,
            'on': INPUT_ON,
            'off': INPUT_OFF,
            'ON': INPUT_ON,
            'OFF': INPUT_OFF,
            null: INPUT_UNDEF,
            'null': INPUT_UNDEF,
            'NULL': INPUT_UNDEF
        };

        // Parser for MainSwitch Input
        const MAIN_INPUT_PARSER = {
            0: 0,
            1: 1,
            2: 2,
            3: 3,
            'OFF': 0,
            'Off': 0,
            'off': 0,
            'ON': 1,
            'On': 1,
            'on': 1,
            'AUTO': 2,
            'Auto': 2,
            'auto': 2,
            'COUNTDOWN': 3,
            'Countdown': 3,
            'countdown': 3
        };

        // intervals for countdown in secs and text
        const TICK_INTERVAL = [
            { secs: 4, text: "4\"" },
            { secs: 7, text: "7\"" },
            { secs: 10, text: "10\"" },
            { secs: 15, text: "15\"" },
            { secs: 20, text: "20\"" },
            { secs: 30, text: "30\"" },
            { secs: 40, text: "40\"" },
            { secs: 50, text: "50\"" },
            { secs: 60, text: "1'" },
            { secs: 120, text: "2'" },
            { secs: 240, text: "4'" },
            { secs: 420, text: "7'" },
            { secs: 600, text: "10'" },
            { secs: 900, text: "15'" },
            { secs: 1200, text: "20'" },
            { secs: 1800, text: "30'" },
            { secs: 2400, text: "40'" },
            { secs: 3000, text: "50'" },
            { secs: 3600, text: "60'" },
            { secs: 5400, text: "90'" },
            { secs: 7200, text: '2h' },
            { secs: 14400, text: '4h' },
            { secs: 21600, text: '6h' },
            { secs: 28800, text: '8h' },
            { secs: 43200, text: '12h' },
            { secs: 64800, text: '18h' },
            { secs: 86400, text: '24h' },
            { secs: 172800, text: '48h' },
            { secs: 259200, text: '72h' },
        ];

        // default colors
        const COLORS = {
            expansionPanelTitle: 'pink',
            mainSwitch: ['red-darken-1', 'green-darken-1', 'blue-darken-1', 'black', 'white'],
            mainSwitchAuto: {
                false: {false: 'red-darken-1', true: 'green-darken-1', null: 'grey-darken-1'},
                true: {false: 'red-lighten-3', true: 'green-lighten-3', null: 'grey-lighten-2'}
            },
            inhibition: ['brown-lighten-3', 'purple', 'grey'],
            inhibitionToolbar: 'blue-lighten-3',
            measurements: ['light-blue-lighten-3'],
            autoIn: {false: 'light-blue-lighten-3', true: 'yellow-lighten-2'},
            timerIn: {false: 'light-blue-lighten-3', true: 'yellow-lighten-2'},
            feedback: {false: 'red-darken-1', true: 'green-darken-1', null: 'grey-darken-1'},
            countdown: 'deep-purple',
            eventToolbar: 'amber',
            slider: 'amber',
            plus: 'red',
            activeActive: 'green',
            activeInactive: 'red',
        };

        // helper function for calculating, on what weekday and what time an event occurs
        function checkWeekdays(days, now, weekday, day, hours, minutes, state) {
            var dates = []; // one item per day

            // for every day
            days.forEach(function (d, j) {
                var date = new Date();
                var dateDay = day - weekday + j;
                date.setDate(dateDay);
                date.setSeconds(0);
                date.setMilliseconds(0);
                date.setHours(parseInt(hours));
                date.setMinutes(parseInt(minutes));
                if (date < now) date.setDate(dateDay + 7)
                    if (d == true) dates.push({ time: date, state: state }) //only if weekdayday is checked
            });

            return dates;
        }

        // calculate the next event to take place in the timer
        function nextTakePlace(events) {
            const now = new Date();
            const weekday = now.getDay();
            const day = parseInt(
                Intl.DateTimeFormat('de-DE', { day: 'numeric' }).format(now)
            );

            var ntp = []; // one item per event and state (true/false)
            // for every event
            events.forEach(function (e, i) {
                if (e.active === true) { // event active?

                    // get start and end, hors and minutes
                    var startHour = parseInt(e.startTime.split(':')[0])
                    var startMinute = parseInt(e.startTime.split(':')[1])
                    var endHour = parseInt(e.duration.split(':')[0]) + startHour
                    var endMinute = parseInt(e.duration.split(':')[1]) + startMinute

                    // generating "On" Times
                    ntp = ntp.concat(
                        checkWeekdays(e.day, now, weekday, day, startHour, startMinute, true)
                    );

                    // generating "Off" Times
                    ntp = ntp.concat(
                        checkWeekdays(e.day, now, weekday, day, endHour, endMinute, false)
                    );
                }
            });

            if (ntp.length == 0) { // no events?
                return [null, false];
            } else {
                // get the next event
                var orderNtp = ntp.sort(function (a, b) {
                    return Date.parse(a.time) - Date.parse(b.time)
                });
                return orderNtp[0];
            }
        }

        // to be executed every second: countdown running? event occurring?
        function ticker (sta) {
            var now = new Date();

            // countdown
            if (sta.countdownSec >= 0) { // active?
                if (sta.countdownSec == 0) { // Countdown run down?
                    node.status.mainSwitch = node.lastMainSwitch; // set to last state before countdown
                    stateMachine();
                }
                node.status.countdownSec = sta.countdownSec - 1; // count down
            }

            // timer events
            if (node.timerNextEvent['time'] < now) { // event takes place?
                node.status.auto = node.timerNextEvent['state']; // set state
                node.status.timerIn = node.timerNextEvent['state'];
                node.status.lastSetter = "timer"; // who did set that state?
                updateEvents(); // generate next event
                stateMachine();
            }

            // calculate next time and state to display in widget
            if (node.timerNextEvent['time']) {
                node.status.timerNextEventSec = Math.floor((node.timerNextEvent['time'] - now) / 1000);
                node.status.timerNextEventState = node.timerNextEvent['state'];
                node.status.timerRunning = TIMER_RUNNING;
            } else { // no event
                node.status.timerNextEventSec = null;
                node.status.timerRunning = TIMER_NOT_RUNNING;
            }

            // send to widget
            updateStatus()
        }

        // send status to widget
        function updateStatus() { // update widget
            base.emit('updateStatus:' + node.id, { payload: node.status }, node);
        }

        // calculate the next occurence of a timer event
        function updateEvents() {
            node.timerNextEvent = nextTakePlace(node.status.events)
        }

        // manage some things when the mainSwitch state changes
        function setMainSwitch(input) {
            // countdown?
            if (input == 3 && node.status.interval !== undefined){
                node.status.countdownSec = node.status.intervalSecs;

                // preserv mainSwitch status for the next change from auto to ?
                if (node.status.mainSwitch == 2) {
                    node.lastMainSwitch = 2; 
                    node.status.switchToText = 'Auto';
                } else {
                    node.lastMainSwitch = 0;
                    node.status.switchToText = 'Off';
                }
            }

            node.status.mainSwitch = input;
            updateStatus();
            stateMachine();
        }

        // send output
        function mainswitchOut(out) {
            // output topic set?
            if (node.topicOut !== "") {
                node.send( {
                    payload: out,
                    topic: node.topicOut
                });
            } else {
                node.send({
                    payload: out
                });
            }
        }

        // bring the things together
        function stateMachine() {
            switch (node.status.mainSwitch) {
                case 0:
                    mainswitchOut(OUT_OFF);
                    node.status.countdownSec = -1; // reset Countdown (potentially)
                    break;
                case 1:
                    mainswitchOut(OUT_ON);
                    node.status.countdownSec = -1; // reset Coundown (potentially)
                    break;
                case 2:
                    if (node.status.auto === AUTO_ON) {
                        mainswitchOut(OUT_ON);
                    } else {
                        mainswitchOut(OUT_OFF);
                    }
                    node.status.countdownSec = -1; // reset Countdown (potentially)
                    break;
                case 3:
                    mainswitchOut(OUT_ON);
                    break;
                default: // only for prevention
                    mainswitchOut(OUT_OFF)
            }
        }

        // manage all potential inputs
        function parseBool(input) {
            if (input in BOOL_INPUT_PARSER) {
                return BOOL_INPUT_PARSER[input];
            } else {
                return INPUT_NOT_SET;
            }
        }

        // merge the default setting objects with the config from html
        function objectMerger(source, coloring) {
            // is the current layer an object/array or not?
            if (typeof(source) == 'object') {
                // ist the current layer an object or array?
                if (Array.isArray(source)) { // array
                    // something to replace?
                    if (coloring === undefined) {
                        return source;
                    } else {
                        var resultArray = [];
                        // walk through the elements of the array
                        source.forEach((el, i) => {
                            resultArray.push(objectMerger(source[i], coloring[i]));
                        });
                        return resultArray;
                    }
                } else { // object
                    var resultObject = {}
                    // walk through the elements of the object
                    for(var key in source){
                        if(source.hasOwnProperty(key)){
                            // something to replace?
                            if (coloring.hasOwnProperty(key)){
                                 resultObject[key] = objectMerger(source[key], coloring[key]);
                            } else {
                                 resultObject[key] = source[key];
                            }
                        }
                    }
                    return resultObject;
                }
            } else { // no object or array
                // something to replace?
                if (coloring !== undefined){
                    return coloring;
                } else {
                    return source;
                }
            }
        }

        // server-side event handlers
        const evts = {
            onAction: true,

            onInput: function (msg, send, done) {
                // without topic -> mainSwitch
                if (msg.topic == "") {
                    if (msg.payload in MAIN_INPUT_PARSER) { // parse all potential inputs
                        setMainSwitch(MAIN_INPUT_PARSER[msg.payload]);
                    }
                }

                // with topic "interval" -> set the intervall for the countdown
                if (msg.topic == "interval") {
                    var interval = parseInt(msg.payload);
                    if (interval >= 0 && interval <= TICK_INTERVAL.length) { // check the allouwed values
                        node.status.interval = interval;
                        //node.status.interval = TICK_INTERVAL[interval]['text'];
                        node.status.intervalSecs = TICK_INTERVAL[interval]['secs'];
                        updateStatus(); // to widget
                    }
                }

                // for feedback from actuator
                if (node.topicFeedback != "" && msg.topic == node.topicFeedback) {
                    node.status.feedback = parseBool(msg.payload);
                    updateStatus(); // to widget
                }

                // for autoIn
                if (node.topicAuto != "" && msg.topic == node.topicAuto) {
                    node.status.auto = parseBool(msg.payload); // for the stateMachine
                    node.status.autoIn = parseBool(msg.payload); // for the chip in the widget
                    node.status.lastSetter = "autoIn"; // highlight what input set auto
                    updateStatus(); // to widget
                    stateMachine(); // switch output?
                }
            },

            onSocket: {
                // widget sends change of mainSwitch
                'downMainswitch': function (conn, id, msg) {
                    // console.info('"downMainswitch" received:', conn.id, id, msg)
                    setMainSwitch(msg.payload);
                },

                // widget sends change of countdown interval
                'downInterval': function (conn, id, msg) {
                    // console.info('"downInterval" received:', conn.id, id, msg)
                    node.status.interval = msg.payload;
                    node.status.intervalSecs = msg.secs;
                    updateStatus(); // to widget
                },

                // widget sends changes from timer event form
                'downEvents': function (conn, id, msg) {
                    // console.info('"downEvents" received:', conn.id, id, msg)
                    node.status.events = msg.payload;
                    context.set('events', node.status.events); // store in context store
                    updateEvents();
                    updateStatus(); // to widget
                },

                // widget askes for actual status
                'update-status': function (conn, id, msg) {
                    // console.info('"update-status" received:', conn.id, id)
                    updateStatus() // to widget
                }
            }
        }

        // get config from html and prepare the node
        this.topicOut = config.topicOut;
        this.topicFeedback = config.topicFeedback;
        this.topicAuto = config.topicAuto;

        // variables for the node
        this.timerNextEvent = {};
        this.lastMainSwitch = 0;
        this.status = {
            mainSwitch: 0,
            interval: 14,
            intervalSecs: 1200,
            auto: AUTO_UNDEF,
            autoIn: INPUT_UNDEF,
            feedback: INPUT_UNDEF,
            countdownSec: -1,
            switchToText: 'Off',
            events: [],
            timerIn: TIMER_UNDEF,
            timerRunning: TIMER_NOT_RUNNING,
            timerNextEventSec: -1,
            timerNextEventState: false,
            lastSetter: ""
        };

        // extend config for the widget
        config.tickInterval = TICK_INTERVAL;
        config.colors = objectMerger(COLORS, JSON.parse(config.colorsCustom));
// console.log(JSON.stringify(COLORS))

        // get context store
        var context = this.context();

        // this is the node
        var node = this;

        // load timer events from the context store
        node.status.events = context.get('events') || [];
        updateEvents();

        // run ticker every second
        var tick = setInterval(ticker, 1000, node.status);
 
        // kill the ticker
        node.on("close", function () {
            if (tick) { clearIntervall(tick); }
        });

        // inform the dashboard UI that we are adding this node
        if (group) {
            group.register(node, config, evts);
        } else {
            node.error('No group configured');
        }
    }

    RED.nodes.registerType('ui-mainswitch', UIMainswitchNode);
}

```

---

<div class="post-metadata">

**Author:** ![Paul-Reed](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/paul-reed/32/66906_2.png) [@Paul-Reed](https://discourse.nodered.org/u/Paul-Reed)\
**Post date:** [21 September 2024 19:54 UTC](https://discourse.nodered.org/t/clearinterval-not-working/91169/2 "2024-09-21T19:54:23Z")

</div>

Shouldn't that be -

```auto
node.on("close", function () {
    if (tick) { clearInterval(tick); } // Corrected clearIntervall to clearInterval
});

```

---

<div class="post-metadata">

**Author:** ![wangenkuesse](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/wangenkuesse/32/93551_2.png) [@wangenkuesse](https://discourse.nodered.org/u/wangenkuesse)\
**Post date:** [21 September 2024 20:02 UTC](https://discourse.nodered.org/t/clearinterval-not-working/91169/3 "2024-09-21T20:02:38Z")

</div>

Ups... you are right... But clearInterval() without the second german "l" didn't solve the problem.

```auto
        node.on("close", function () {
            if (tick) { clearInterval(tick); }
        });

```

the same: two ticks per second.

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [21 September 2024 20:05 UTC](https://discourse.nodered.org/t/clearinterval-not-working/91169/4 "2024-09-21T20:05:52Z")

</div>

> [@wangenkuesse](#):
>
> cleaInterval() is not stopping the function. The function is called two times per second. One Instance is out of context.

~~Sorry, maybe I'm tired but I can't see an issue with that.~~ I think you need to switch to a better code editor. When I pasted that code into VScode and started looking at the errors it generated, I spotted the problem immediately (well, to be fair, VSCode did): `clearIntervall` instead of `clearInterval`.

I did spot some other things that might come to haunt you though.

> [@wangenkuesse](#):
>
> `var tick`

Use `const tick`, don't use var unless there is no alternative so as to avoid scope and memory leak issues.

I see you also use `var node = this` - Personally I never do that any more and even if I did, I wouldn't use `var`, it should be `const`.

> [@wangenkuesse](#):
>
> `if (msg.topic == "interval") {`

Always use `===`, `!==`, etc except in the rare occasions you may need to check a number that might come in as a string representation. Inexact comparisons can lead to really hard to find bugs.

---

<div class="post-metadata">

**Author:** ![Paul-Reed](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/paul-reed/32/66906_2.png) [@Paul-Reed](https://discourse.nodered.org/u/Paul-Reed)\
**Post date:** [21 September 2024 20:13 UTC](https://discourse.nodered.org/t/clearinterval-not-working/91169/5 "2024-09-21T20:13:47Z")

</div>

Is it because you are not storing the timer handle? see my previous posted example -

> [@clearTimeout not function](https://discourse.nodered.org/t/cleartimeout-not-function/90870/3):
>
> Like this @wilson2517 ... var entrada = msg.payload; var testset = context.get("testset"); // Retrieve the stored timeout reference if (entrada == "on") { testset = setTimeout(function() { msg.payload = "active"; node.send(msg); }, 2000); context.set("testset", testset); // Store the timeout reference for future use } if (entrada == "off") { clearTimeout(testset); // Clear the timeout context.set("testset", null); // Clear the stored timeout reference…

---

<div class="post-metadata">

**Author:** ![wangenkuesse](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/wangenkuesse/32/93551_2.png) [@wangenkuesse](https://discourse.nodered.org/u/wangenkuesse)\
**Post date:** [21 September 2024 20:18 UTC](https://discourse.nodered.org/t/clearinterval-not-working/91169/6 "2024-09-21T20:18:27Z")

</div>

> [@Paul-Reed](#):
>
> Is it because you are not storing the timer handle?

I would expect

```auto
        node.on("close", function () {
            if (tick) { clearInterval(tick); }
        });

```

to be executed when stopping the flow on deploy???

---

<div class="post-metadata">

**Author:** ![marcus-j-davies](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/marcus-j-davies/32/103435_2.png) [@marcus-j-davies](https://discourse.nodered.org/u/marcus-j-davies)\
**Post date:** [21 September 2024 20:19 UTC](https://discourse.nodered.org/t/clearinterval-not-working/91169/7 "2024-09-21T20:19:21Z")

</div>

Just my 2c

Use a `let` variable outside the init block and assign it the interval object within the init block later.

I wonder if the `var` is falling out of scope after the init has executed, and being Garbage Collected?

Just a guess

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [21 September 2024 20:21 UTC](https://discourse.nodered.org/t/clearinterval-not-working/91169/8 "2024-09-21T20:21:17Z")

</div>

> [@wangenkuesse](#):
>
> I would expect

So would I.

> [@Paul-Reed](#):
>
> Is it because you are not storing the timer handle

I don't think that is the case - that code will be live while Node-RED is live. A deploy will restart that outer function once the inner on-close has finished. Though you could add a call to `done()` just to be ultra-cautious.

```javascript
node.on("close", (removed, done) => {
     if (tick) { clearInterval(tick); }
     done();
});

```

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [21 September 2024 20:31 UTC](https://discourse.nodered.org/t/clearinterval-not-working/91169/9 "2024-09-21T20:31:15Z")

</div>

> [@wangenkuesse](#):
>
> ```auto
> // Parser for boolean Input
> const BOOL_INPUT_PARSER = {
> 
> ```

By the way, I use a small function for that rather than a big long list:

```js
    /** Returns true/false or a default value for truthy/falsy and other values
     * @param {string|number|boolean|*} val The value to test
     * @param {any} deflt Default value to use if the value is not truthy/falsy
     * @returns {boolean|any} The truth! Or the default
     */
    truthy(val, deflt) {
        let ret
        if (['on', 'On', 'ON', 'true', 'True', 'TRUE', '1', true, 1].includes(val)) ret = true
        else if (['off', 'Off', 'OFF', 'false', 'False', 'FALSE', '0', false, 0].includes(val)) ret = false
        else ret = deflt
        return ret
    }

```

It allows you to also specify an optional default value.

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [21 September 2024 20:32 UTC](https://discourse.nodered.org/t/clearinterval-not-working/91169/10 "2024-09-21T20:32:48Z")

</div>

Add some console logging so you can see what is being executed. See whether the problem is with the variable or if on close is not being called.

---

<div class="post-metadata">

**Author:** ![wangenkuesse](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/wangenkuesse/32/93551_2.png) [@wangenkuesse](https://discourse.nodered.org/u/wangenkuesse)\
**Post date:** [21 September 2024 20:43 UTC](https://discourse.nodered.org/t/clearinterval-not-working/91169/11 "2024-09-21T20:43:50Z")

</div>

now it is:

```auto
        // run ticker every second
        const tick = setInterval(ticker, 1000, node.status);
 
        // kill the ticker
        node.on("close", function () {
            console.log("onClose")
            if (tick) { 
                console.log("onClear")
                clearInterval(tick); }
            done()
        });

```

the log on deploy is:

```auto
21 Sep 22:41:08 - [debug] saved flow revision: 7a0da80525c1fada56fa9d4d698286a093d5d865b046f0f5fce0586c0b262083
21 Sep 22:41:08 - [info] Stopping flows
21 Sep 22:41:08 - [debug] red/nodes/flows.stop : stopping flow : 316730b04d105032
onClose
onClear
21 Sep 22:41:08 - [debug] red/nodes/flows.stop : stopping flow : global
21 Sep 22:41:08 - [info] Stopped flows
21 Sep 22:41:08 - [info] Updated flows
21 Sep 22:41:08 - [info] Starting flows

```

same problem, two ticks per second

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [21 September 2024 20:59 UTC](https://discourse.nodered.org/t/clearinterval-not-working/91169/12 "2024-09-21T20:59:08Z")

</div>

Maybe put a log into the ticker fn - make sure you include the node.id in the debug output.

---

<div class="post-metadata">

**Author:** ![marcus-j-davies](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/marcus-j-davies/32/103435_2.png) [@marcus-j-davies](https://discourse.nodered.org/u/marcus-j-davies)\
**Post date:** [21 September 2024 21:12 UTC](https://discourse.nodered.org/t/clearinterval-not-working/91169/13 "2024-09-21T21:12:29Z")

</div>

Another potential.

Use an arrow function

```auto
node.on('close', (removed, done) => {
    if (tick) { clearInterval(tick); }
    done();
})

```

I don't really understand the science behind it, but the closure function does not take `this` into consideration (at least what you think `this` is) - as the event function is being executed by a different `this`, and a function (I think) carries the `this` from the caller (or something like that)

arrow functions refer to `this` as the parenting body, and `tick`, belongs to the true `this`, not the `this`, that the event is being fired from

I might not have this correct - but worth to investigate maybe

---

<div class="post-metadata">

**Author:** ![wangenkuesse](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/wangenkuesse/32/93551_2.png) [@wangenkuesse](https://discourse.nodered.org/u/wangenkuesse)\
**Post date:** [21 September 2024 21:35 UTC](https://discourse.nodered.org/t/clearinterval-not-working/91169/14 "2024-09-21T21:35:41Z")

</div>

I changed nothing but adding the logging to the ticker fn. Now I have one execution of the ticker every second ?????

Thank you everybody. Time for me to turn the ticker fn right to left.

```auto
680b84bbc7022ae8
2024-09-21T21:21:51.363Z
21 Sep 23:21:52 - [debug] saved flow revision: 7a0da80525c1fada56fa9d4d698286a093d5d865b046f0f5fce0586c0b262083
21 Sep 23:21:52 - [info] Stopping flows
21 Sep 23:21:52 - [debug] red/nodes/flows.stop : stopping flow : 316730b04d105032
onClose
onClear
21 Sep 23:21:52 - [debug] red/nodes/flows.stop : stopping flow : global
21 Sep 23:21:52 - [info] Stopped flows
21 Sep 23:21:52 - [info] Updated flows
21 Sep 23:21:52 - [info] Starting flows
21 Sep 23:21:52 - [debug] red/nodes/flows.start : starting flow : global
21 Sep 23:21:52 - [debug] red/nodes/flows.start : starting flow : 316730b04d105032
21 Sep 23:21:52 - [info] Started flows
680b84bbc7022ae8
2024-09-21T21:21:53.224Z
680b84bbc7022ae8
2024-09-21T21:21:54.226Z
680b84bbc7022ae8
2024-09-21T21:21:55.227Z
680b84bbc7022ae8
2024-09-21T21:21:56.229Z
680b84bbc7022ae8
2024-09-21T21:21:57.228Z
680b84bbc7022ae8
2024-09-21T21:21:58.229Z
680b84bbc7022ae8
2024-09-21T21:21:59.231Z

```

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [22 September 2024 08:54 UTC](https://discourse.nodered.org/t/clearinterval-not-working/91169/15 "2024-09-22T08:54:33Z")

</div>

> [@marcus-j-davies](#):
>
> I might not have this correct

You do have it right and the complex nature of Node-RED nodes does make the handling of `this` a little complex as it doesn't always do what you expect. That is why you'll see I've very much changed the structure of my nodes from the structure given in the original example node that most people copy.

It took me quite a while to investigate and understand how and when `this` gets created and where it can be used vs where you need to pass it in a fn call.

But doing so really helped me simplify my more complex nodes a lot. Also, having a standard structure for your nodes lets you focus more on the logic and less on the slip-ups - well it does for me anyway, your mileage may vary of course. 🙂

Having said all that though. In this case, it wouldn't make a difference because the closure fn isn't using `this` at all but rather just the var from the outer fn.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [6 October 2024 08:55 UTC](https://discourse.nodered.org/t/clearinterval-not-working/91169/16 "2024-10-06T08:55:13Z")

</div>

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.
