在Javascript中轮询本地值的首选方法?

时间:2015-05-26 06:46:34

标签: javascript jquery node.js asynchronous settimeout

例如,有一个名为animationComplete的变量(来自第三方库)和一个名为happenAfterAnimation的函数:

一个简单的解决方案如下:

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

或者像这样的更复杂的解决方案:

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

}
setTimeout(tryHappenAfterAnimation, 100)

第一个解决方案可能有一些开销,第二个解决方案看起来有点脏。

由于future/promise在当前版本的Javascript中不可用,所以这里可能有点矫枉过正.. 我只是想知道这种情况是否有优雅轻巧的方式..

有没有人对更好的处理方法有想法?谢谢!

3 个答案:

答案 0 :(得分:3)

第一种方法根本不起作用。它将永远阻止该线程。

缺乏内置的承诺支持并不是不使用承诺的借口。如果你的图书馆给你一个事件/回调驱动的方式来等待结果(如果它没有,我会感到惊讶),那么你应该使用一个事件或承诺。

如果没有,并且轮询变量真的是你唯一的选择,那么我会说你的第二种方法几乎是唯一的选择。

答案 1 :(得分:2)

快速摘要 - 你的第一个方法不起作用(它只是一个无限循环)和一个轮询机制(虽然可以使它工作)绝不是“首选”的选择。

Javascript是单线程的(有一些例外,比如webWorkers,但它们在这里不适用)所以只要你的while循环运行,没有其他JS可以运行,可能会改变animationComplete的值所以你将拥有一个永远无法完成的无限循环(最终浏览器会抱怨JS线程尚未完成,并为用户提供了停止脚本的机会)。

知道动画何时完成的正确方法是使用回调来完成动画。如果您正在使用jQuery,那么所有jQuery动画都有一个完成回调,您可以传递它,并在动画完成时调用它。然后,在回调函数中放置动画后想要发生的代码。

如果你正在使用CSS3动画,那么你可以为transitionend事件注册一个事件处理程序,并在动画完成后以这种方式获得回调。

如果您确实想要轮询变量的值,那么使用计时器轮询它将是一个合适的选择,因为这允许其他代码运行,实际上可以更改变量。

我应该补充一点,像这样的民意调查很少是最好的设计选择。如果它是动画,那么您只想在动画上使用完成事件,因此不需要轮询。如果由于某种原因,你使用的是没有内置完成事件的动画函数,则可能值得修改该代码以包含这样的回调,因为它总是可行的并且显然是有用的。

为了让我们提供更详细的建议,我们需要了解更多有关动画代码以及您要做的事情。正如我之前所说,所有jQuery动画都提供了对完成通知的承诺和回调支持(你确实标记了jQuery的问题,这就是我提到的原因)。

任何接口中缺少promise都不是不使用完成回调的理由,因此事实在这里并不真正相关,并且任何给定的函数也可以被实现(将普通回调转换为promise接口)如果promises是与异步事件交互的理想方式。

答案 2 :(得分:1)

这是一种基于Promises的方法。以下实现了定期轮询以及超时。

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;
        });
}

你这样称呼它。

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

请参阅Javascript polling with promises