Multiple setTimeout/clearTimeout Within Same Function Node

Not dense, it isn't obvious if you've not done it before.

The trick is to remember that a set timer returns a timer object reference. So you have to assign to a variable. Then you can track/clear multiple timers.

Still looking at your flow yet but that is the basics.

From your flow, you are not saving the timers to context so they will be created/lost on each incoming msg.


Since I had a few minutes and the excercise was good for me, here is a working example - note that you need to change your triggers to use boolean inputs rather than text.


function timer1 () {
    // This runs when the timer expires
    // msg is set to the incoming msg at the time the timer was created
    node.send(msg)
    node.warn('TIMER IS SELF CANCELLING FOR TOPIC ' + msg.topic )
    // Delete the entry from the context var and write back
    delete timers[msg.topic]
    context.set('timers', timers)
}

// Get the timers from the context store
let timers = context.get('timers') || {}

// Is there an existing timer for this topic?
if ( timers[msg.topic] ) {
    // If so, is the NEW payload TRUE?
    if ( msg.payload === true ) {
        // Cancel the timer & delete from context
        node.warn('CANCELLING TIMER FOR EXISTING TOPIC ' + msg.topic )
        clearTimeout(timers[msg.topic])
        delete timers[msg.topic]
    } else {
        // NEW payload is FALSE so create a timer
        // NB: timouts cancel themselves when they run
        node.warn('CREATING NEW TIMER FOR EXISTING TOPIC ' + msg.topic )
        timers[msg.topic] = setTimeout(timer1, 5000)
    }
} else {
    // Only interested in a payload of FALSE since 
    // there will be no timer to cancel in this case
    if ( msg.payload === false ) {
        // NEW payload is FALSE so create a timer
        // NB: timouts cancel themselves when they run
        node.warn('CREATING NEW TIMER FOR NEW TOPIC ' + msg.topic )
        timers[msg.topic] = setTimeout(timer1, 5000)
    }
}

// Update the timers to the context store
context.set('timers', timers)

You could refactor that code slightly to simplify the nested if's.

I also suspect that it would be possible to get race conditions with this code if you were sending through topics and cancelling them faster than the timeout value.

2 Likes