requestAnimationFrame API-在密集JavaScript函数期间设置动画

requestAnimationFrame API-在密集JavaScript函数期间设置动画,javascript,requestanimationframe,Javascript,Requestanimationframe,我在web应用程序中有一个长时间的线程阻塞功能。在执行过程中,我想显示一个动画图标。我想使用Window。requestAnimationFrame()。我接触过的资料来源有: 我明白,我需要一个函数——我称之为animateLoadingIcon()——来更新我的绘图。在其函数体中,我必须最终调用requestAnimationFrame(animateLoadingIcon)来开始视图的递归更新 在下面找到函数animateLoadingIcon,该函数根据调用后经过的时间计算

我在web应用程序中有一个长时间的线程阻塞功能。在执行过程中,我想显示一个动画图标。我想使用Window。requestAnimationFrame()。我接触过的资料来源有:


我明白,我需要一个函数——我称之为animateLoadingIcon()——来更新我的绘图。在其函数体中,我必须最终调用requestAnimationFrame(animateLoadingIcon)来开始视图的递归更新

在下面找到函数animateLoadingIcon,该函数根据调用后经过的时间计算图标的旋转角度

function animateLoadingIcon() {
rotateCount = (new Date().getTime() - starttime) / 3;
if (rotateCount > 359) {
  rotateCount %= 360;
}
divLoadingIcon.style.transform = 'rotate(' + rotateCount + 'deg)';
requestedAnimationFrame = requestAnimationFrame(animateLoadingIcon);
}

我最初想要执行的函数是calc(),其中调用了animateLoadingIcon()

function calc() {

let randomMills = Math.random()*6000;
console.log("Start with duration: " + randomMills +"ms.")

starttime = new Date().getTime();
let recentTime = new Date().getTime();

let i = 0;

animateLoadingIcon();   
while (recentTime < starttime+randomMills) {
    i++;
    isPrime(i);
    recentTime = new Date().getTime();

} 
cancelAnimationFrame(requestedAnimationFrame);    
函数计算(){
让randomMills=Math.random()*6000;
log(“以持续时间开始:+randomMills+“ms.”)
starttime=新日期().getTime();
让recentTime=newdate().getTime();
设i=0;
animateLoadingIcon();
而(最近时间<开始时间+随机时间){
i++;
优先权(i);
recentTime=新日期().getTime();
} 
取消动画帧(请求动画帧);
}

当我点击按钮时,我期望轮子转动,当while循环离开时,轮子停止转动。但事实并非如此。有人能指出我的错误吗

请在下面找到一个JSFIDLE示例 这是一个更好的解决方案,也是实现这一目标的“正确”方法

使用Promise和,使用setTimeout循环而不是while循环,以便在事件循环中延迟对isPrime的每次调用和每次循环迭代,并允许在其间执行动画

JSFIDLE演示:

等待新的承诺(res=>{
变量循环=()=>{
var tid=setTimeout(()=>{
如果(最近时间<开始时间+随机时间){
i++;
优先权(i);
recentTime=新日期().getTime();
循环()
}else{clearTimeout(tid);res();}
}, 0)
};
循环()
});
不太漂亮,肯定可以写得更优雅,但它确实有效。异步函数循环可能也可以作为一个等效的单行程序使用。

当然会有额外的开销,您可能需要对isPrime或您正在调用的任何东西的调用进行分块

感谢所有有用的输入。关于将线程阻塞外包给工作线程的提示是正确的

我现在基本上只打电话

function calc() {

    animateLoadingIcon();   
    worker.postMessage([randomMills, starttime])

}
当工人发出准备就绪事件时,我执行:

worker.onmessage = function (e) {
    cancelAnimationFrame(requestedAnimationFrame);
}

这会将阻止代码放入一个单独的线程中,而requestAnimationFrame可以在主线程中和平运行。

我打赌
while
循环会阻止线程,从而阻止
requestAnimationFrame
循环获得经过渲染阶段的更改。我建议你使用WebWorkers进行密集的计算任务,让主线程专注于DOM操作。好了,我正在挖掘文档,看看这是否有帮助。谢谢你的提示。你的代码没有while循环,cancelAnimationFrame由button.onclick事件触发。所以我认为埃米尔是对的,你们是对的。我把这项繁重的工作外包给了一个员工。您可以在my repo中找到一个工作示例:Hellma:您应该在这里发布您的解决方案(相关代码,然后是github链接)作为答案,并接受它作为解决方案。这可能是Google和future的一个很好的参考线程,作为重复链接,供那些想知道为什么他们的动画被阻止,或者如何防止线程被锁定的人使用。谢谢!我尝试了一种你称之为更好的解决方案:)
worker.onmessage = function (e) {
    cancelAnimationFrame(requestedAnimationFrame);
}