例如,有一个名为animationComplete
的变量(来自第三方库)和一个名为happenAfterAnimation
的函数:
一个简单的解决方案如下:
while(!animationComplete) {
// Do nothing
}
happenAfterAnimation()
或者像这样的更复杂的解决方案:
function tryHappenAfterAnimation() {
if(animationComplete) {
happenAfterAnimation()
} else {
setTimeout(tryHappenAfterAnimation, 100)
}
}
setTimeout(tryHappenAfterAnimation, 100)
第一个解决方案可能有一些开销,第二个解决方案看起来有点脏。
由于future/promise
在当前版本的Javascript中不可用,所以这里可能有点矫枉过正..
我只是想知道这种情况是否有优雅轻巧的方式..
有没有人对更好的处理方法有想法?谢谢!
答案 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();
}
);