[SalesForce] Lightning action call inside setTimeout returns result only when window (tab) loses focus

I have a Lightning action call inside a recursive setTimeout call. I call the action immediately and then every 3 seconds until the result it not null.

I see my console.log('tick'); immediately. But I don't see my result (in either the if or the else block) until my window (or tab) loses focus. As soon as it does lose focus, it returns immediately and I see my results as intended.

It may or may not be worth mentioning this action call is inside the callback (the then(…) of a previous action, as denoted by my variable action2.

It also may or may not be worth mentioning that this is all happening on a Lightning Out site.

Also, I'm following the excellent action execution pattern as described by the infamous Bob Buzzard here:

setTimeout(function tick() {
    self.executeAction(component, action2)
    .then($A.getCallback(result => {
        if (result) {
        } else {
            console.log('not yet...');
            setTimeout(tick, 3000)
}, 0);

It undoubtedly has something to do with a missing or improperly placed $A.getcallBack()?

Many thanks.

Best Answer

Yes, you're missing an $A.getCallback. What happens is that you're putting the action in the event queue, but it won't get executed until another Aura event occurs (in this case, either the blur or focus event is causing this). As soon as you go asynchronous, you're outside of the Aura life cycle, so Aura can't respond to any more events until the next time you re-enter the life cycle. The exception to this rule are those Aura methods that expect a callback; those callbacks will always be in the correct part of the Aura life cycle.

In this case, the missing $A.getCallback is in the setTimeout function:

setTimeout($A.getCallback(function tick() { ...

This is why your log appears immediately, but the action doesn't fire until later. This is true for any situation where you're using a native JavaScript callback. This includes native setTimeout, setInterval, onload/onerror/onprogress/etc events for loading files or XMLHttpRequest callouts, and so on.

Related Topic