【问题标题】:Why blocking event loop does not block css animation?为什么阻塞事件循环不会阻塞css动画?
【发布时间】:2019-02-18 21:08:46
【问题描述】:

我不知道网页渲染的生命周期——所以在下面的例子中我有两颗心——一颗由 js 动画,另一颗由 CSS 动画。当我使用alert 消息阻止事件循环时,CSS 心脏保持动画。

let scale = true;
setInterval(() => {
  $('.animate-js').css('transform', `scale(${scale ? 1.4 : 1})`);
  scale = !scale;
}, 1000)
body {
  text-align: center;
}

.heart {
  white-space: nowrap;
  display: inline-block;
  font-size: 150px;
  color: #e00;
  transform-origin: center;
}

.animate-css {
  animation: beat 2s steps(2, end) infinite;
}


/* Heart beat animation */

@keyframes beat {
  to {
    transform: scale(1.4);
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="heart">I
  <div class="animate-css heart">&#x2665;</div> CSS</div>
<div class="heart">I
  <div class="animate-js heart">&#x2665;</div> JS</div>
<br/>
<button onClick="alert('hurray!')">
I love it too
</button>

我很确定这是因为 CSS 动画是在 javascript 事件循环之外处理的,但我不确定我的假设是否正确。最接近解释内部原理的文章是 - Rendering Performance。但是,它还不够深入。如果有人解释这一点或在我开始寻找规格之前向我指出一些易于理解的材料来阅读/观看,我将不胜感激。 在此先感谢

【问题讨论】:

标签: javascript css browser


【解决方案1】:

这是因为规范鼓励实施者不要遵循规范...

alert() 调用pause algorithm,这应该阻塞当前任务并导致事件循环除了等待“条件目标满足”。

虽然,这个页面也有一个很大的警告段落说明,

Pausing 对用户体验非常不利,尤其是在多个文档之间共享单个event loop 的情况下。鼓励用户代理尝试pausing 的替代方案,例如spinning the event loop,或者甚至在没有任何暂停执行的情况下简单地继续进行,只要可以这样做,同时保持与现有内容的兼容性。如果发现一个不那么激烈的替代方案与网络兼容,那么这个规范将会很高兴地改变。

因此,您的 UA 肯定遵循建议尝试使用 spin-the-event-loop 替代方案,这允许其他任务仍然运行,即使调用 alert() 的任务已暂停。

【讨论】:

  • 谢谢@Kaiido!嗯,所以说你的意思是它不应该为 CSS 设置动画,对吧?我最初的猜测是浏览器在与实际 UI 渲染不同的线程中运行 javascript。
  • @Gerard 提到了一个关于合成线程的链接,这意味着 UI 不会“中断”当前任务,而只是在单独的线程中运行 CSS 动画
  • @Ivan 是的,原始算法不允许执行渲染任务。即使它们在不同的线程上运行。但也正是他们要求其他更好的方法。所以可以预料,越来越多的UA实际上走上了旋转的道路。
  • @Ivan 事件循环并不关心完成了多少线程。线程在这里充其量是无关紧要的。
  • 是的,事件循环没有。但事实上,css 动画没有被阻塞的事件循环所冻结,这意味着它不是它的一部分,意味着它是一个单独的线程,对吧?
【解决方案2】:

是的,根据我的阅读,CSS 动画似乎在 Javascript 事件循环之外。但是,当它们同时运行时,您可以通过 Javascript 调用来控制动画。

这里是阅读材料合集:https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations

特别是,animation-play-state 是我认为您需要的属性。在调用 Javascript 警报之前将其设置为 paused 将是我处理它的方式。用户单击警报中的相应按钮后,将属性设置回running 以恢复动画。

【讨论】:

    猜你喜欢
    • 2016-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-16
    • 1970-01-01
    相关资源
    最近更新 更多