指示处理器密集型的JS函数正在运行(GIF旋转器不会动画)。

17

显示然后隐藏动画指示器/旋转图像是向用户展示他们的操作已经完成并且正在等待操作完成时发生了某些事情的好方法,例如,如果该操作需要通过AJAX从服务器加载一些数据。

我的问题是,如果减速的原因是一个处理器-密集型函数,则gif会冻结。

在大多数浏览器中,GIF在处理器耗费资源的函数执行时停止动画。对于用户来说,这看起来像是某些东西已经崩溃或出现故障,而实际上它正在工作。

JSBIN示例

注意: "This is slow"按钮将占用处理器一段时间-对我来说大约10秒,具体取决于电脑配置。您可以通过HTML中的"data-reps"属性更改其执行时间。

enter image description here

  • 期望结果:点击后,动画开始运行。当进程完成时,文本会发生变化(通常我们也会隐藏指示器,但如果保留旋转效果,例子更清晰)。
  • 实际结果:动画开始运行,然后冻结直到进程完成。这会给人一种东西坏了的印象(直到它突然意外地完成)。

如果JS正在繁忙地占用处理器,有没有一种不会冻结的指示进程正在运行的方法? 如果没有办法进行动画,我将显示然后隐藏静态文本消息,说Loading...或类似的内容,但动画看起来更加活跃。


如果有人想知道为什么我使用处理器密集型的代码而不是通过优化避免问题:这涉及到很多必要的复杂渲染。代码相当高效,但它所做的事情很复杂,因此始终会对处理器产生需求。这只需要几秒钟,但足以让用户感到沮丧,有很多研究表明指示器对于用户体验很有帮助

与处理器密集型功能相关的第二个问题是,gif旋转器实际上直到一个同步集中的所有代码都运行完成后才会显示 - 这意味着它通常要等到隐藏旋转器时才会显示旋转器。

  • JSBIN示例
  • 我在这里找到了一个简单的解决方法(在上面的另一个示例中使用),即用非常短的间隔setTimeout( function(){ ... },50);将显示指示器后的所有内容包装在异步函数中。这可以工作(请参见上面的第一个示例),但不是很干净 - 我相信有更好的方法。

我相信在处理器密集型加载方面一定有某种标准方法,但我不知道 - 或者可能只是使用 setTimeoutLoading... 文本?我的搜索没有找到任何结果。我已经阅读了6或7个类似问题的提问,但它们都与此无关。


编辑:评论中有一些很好的建议,这里是我确切问题的更多细节:

  • 复杂的过程涉及处理大型JSON数据文件(即,在加载文件后进行JS数据操作),并呈现SVG(通过Raphael.js)可视化,包括一个复杂、详细的可缩放世界地图,基于从JSON数据处理的结果。因此,其中一些需要DOM操作,而另一些则不需要。
  • 不幸的是,我需要支持IE8但是如果必要,我可以为IE8 / IE9用户提供最小回退,例如Loading...文本,并为其他所有人提供现代化的东西。

1
你有没有考虑将计算密集型的代码移动到Web Worker中? - Pointy
@ssorallen 好主意 - 我通常甚至不考虑CSS3动画,因为我需要支持IE8+(boooo),但如果它有效,IE<10用户可以获得“加载中...”文本,其他人则可以使用CSS3。 - user56reinstatemonica8
1
@user568458 这有点像使用单独的线程。你必须传递消息到/从 Web Worker 代码,因此对于某些应用程序来说很难使用。该机制必须使环境隔离,因为语言中缺少同步原语。 - Pointy
1
很遗憾,Web Workers仅在IE10+中受支持:http://caniuse.com/#feat=webworkers - Ross Allen
1
我很自由地增强了你的小提琴。我已经用FF测试过了,但一切都冻结了。但在Chrome上,红色和绿色的立方体仍然保持着表现 微笑 http://jsbin.com/iCEsoqID/5/edit - TorchMan
显示剩余4条评论
2个回答

7

2
请记住,将动画保持在UI线程之外并不是那么简单。如果动画元素具有任何相对单位(例如百分比),动画仍将冻结。 - leods92
有趣的是,在Chrome中,如果我使用var start = +new Date; while (+new Date - start < 2000){}来卡住处理器,#2、#3和#8在Luke Haas页面上会一直旋转;而在IE10和IE11中,只有#6会一直旋转;在Firefox中,#2和#6会一直旋转...与此同时,所有浏览器在简单的正方形上的行为都是相同的。 - user56reinstatemonica8
经过一些测试后,似乎所有现代浏览器(IE10+和其他浏览器的~2014+版本左右)都允许仅为变换而存在的动画,并且浏览器还允许某些其他东西,但它们在允许的内容上如此不一致,以至于试图跟踪所有这些内容会导致疯狂。简而言之,请使用CSS变换动画。 - user56reinstatemonica8
最后需要注意的是,在某些浏览器上(尤其是IE的所有版本),即使基于“transform”的旋转动画也会因为CPU正在处理大量的绘制/渲染层事件而停止,这可能会导致用户体验问题。例如,进程通过AJAX载入文件,旋转图标开始旋转;处理数据时,如果旋转图标只是基于transforms,则它仍会继续旋转;当它开始呈现一个复杂的新布局时,旋转图标停止旋转,好像已经崩溃了一样。 - user56reinstatemonica8

2

我过去也遇到过类似的问题。最终,通过优化或按照用户操作分成较小的块来进行工作,这些问题都得到了解决。在您的情况下,不同的缩放级别将触发不同的渲染算法。您只需要处理用户可以看到的内容(加上可能的缓冲区余量)。

我认为,对于您而言唯一简单的跨浏览器解决方法是使用setTimeout给UI线程运行的机会。将您的工作分批处理并使用几个setTimeout调用链接它们。这会减慢总处理时间,但至少用户会得到反馈。显然,此建议要求您的处理可以轻松分段。如果是这种情况,您还可以考虑添加进度条以改善用户体验。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接