Hanfei Sun
Hanfei Sun

Reputation: 47071

Preferred way to poll a local value in Javascript?

For example, there is a variable called animationComplete (from a 3rd-party library) and a function called happenAfterAnimation:

A simple solution looks like this:

while(!animationComplete) {
   // Do nothing
}
happenAfterAnimation()

Or a more complex solution like this:

function tryHappenAfterAnimation() {
  if(animationComplete) {
    happenAfterAnimation()
  } else {
    setTimeout(tryHappenAfterAnimation, 100)
  }

}
setTimeout(tryHappenAfterAnimation, 100)

The first solution may have some overheads, and the second solution looks a bit dirty.

As future/promise is not available in current version of Javascript, it way may be a bit overkill here.. I was just wondering whether there is an elegant and lightweight way for this situation..

Does anyone have ideas about the better way to deal with this? Thanks!

Upvotes: 11

Views: 2201

Answers (3)

W.P. McNeill
W.P. McNeill

Reputation: 17066

Here is an approach based on Promises. The following implements periodic polling along with a timeout.

var Promise = require('bluebird');

/**
 * Periodically poll a signal function until either it returns true or a timeout is reached.
 *
 * @param signal function that returns true when the polled operation is complete
 * @param interval time interval between polls in milliseconds
 * @param timeout period of time before giving up on polling
 * @returns true if the signal function returned true, false if the operation timed out
 */
function poll(signal, interval, timeout) {
    function pollRecursive() {
        return signal() ? Promise.resolve(true) : Promise.delay(interval).then(pollRecursive);
    }

    return pollRecursive()
        .cancellable()
        .timeout(timeout)
        .catch(Promise.TimeoutError, Promise.CancellationError,function () {
            return false;
        });
}

You call it like so.

poll(animationComplete, pollingInterval, timeout)
    .then(function(complete) {
        if (complete)
            happenAfterAnimation();
    }
);

See Javascript polling with promises.

Upvotes: 2

jfriend00
jfriend00

Reputation: 707836

Quick summary - Your first method will not work (it will just be an infinite loop) and a polling mechanism (while it can be made to work) is never the "preferred" choice.

Javascript is single threaded (with some exceptions like webWorkers, but they don't apply here) so as long as your while loop is running, no other JS can run that could possibly change the value of animationComplete so you would have an infinite loop that will never complete (eventually the browser will complain that the JS thread has not completed and offer the user a chance to stop the script).

The proper way to know when an animation is complete is to use a callback for the completion of the animation. If you're using jQuery, then all jQuery animations have a completion callback which you can pass and it will get called when the animation is done. You then put the code that you want to have happen after the animation in that callback function.

If you're using CSS3 animations, then you can register an event handler for the transitionend event and get a callback that way when the animation is complete.

If you did want to poll the value of a variable, then using a timer to poll it would be an appropriate choice as this allows other code to run that could actually change the variable.

I should add that polling like this is rarely the best design choice. If it's an animation, then you just want to use a completion event on the animation so no polling is required. If, for some reason, you're using an animation function that doesn't have a completion event built-in, then it's probably worth modifying that code to include such a callback as it will always be possible and is obviously useful.


For us to provide a more detailed recommendation, we would need to know more about the animation code and what you're trying to do. As I said before, all jQuery animations provide both promise and callback support for completion notification (you did tag the question jQuery is why I mention that).

A lack of promises in any interface is not a reason to not use completion callbacks so that fact isn't really relevant here and any given function can be promisified too (turn a plain callback into a promise interface) if promises are the desired way to interact with async events.

Upvotes: 3

JLRishe
JLRishe

Reputation: 101738

The first approach will not work at all. It will block the thread forever.

The absence of built-in promise support isn't really an excuse not to use promises. If your library gives you an event/callback-driven way to wait on the results (and I would be surprised if it didn't), then you should use an event, or promises.

If not, and polling the variable is really your only option, then I would say your second approach is pretty much the only option.

Upvotes: 4

Related Questions