如何在Javascript中制作精确的睡眠功能,可能使用承诺?
Posted
技术标签:
【中文标题】如何在Javascript中制作精确的睡眠功能,可能使用承诺?【英文标题】:How to make a precise sleep function in Javascript, possibly using promises? 【发布时间】:2020-08-16 19:31:11 【问题描述】:我正在尝试在 javascript 中创建睡眠功能。
drawLinesTohtmlCanvas()
函数用于在 HTML 画布上绘制随机线条,用户可以实时看到正在绘制的线条。
对于这个例子,我使用了 500 毫秒的延迟,但希望能够达到 1 毫秒(或者将来甚至小于 1 毫秒的分辨率)
最初我遵循了这篇文章的答案:What is the JavaScript version of sleep()?
function sleep(ms)
return new Promise(resolve => setTimeout(resolve, ms));
async function drawLinesToHtmlCanvas()
// Get canvas and context here...
var drawSpeed = 500; // ms.
for (i=0; i<lines; i++)
// Draw lines to canvas...
await sleep(drawSpeed);
而且效果很好(上图)。它很高效,完全没有减慢浏览器的速度,让我可以控制时间。
问题是setTimeout()
似乎无法降低到 1 毫秒的精度,而这是我对这个函数所需要的。
所以我尝试了自己的方法如下:
function sleep(ms)
ms = parseInt(ms);
var now = new Date();
nowMs = now.valueOf();
var endMs = nowMs + ms;
while (endMs > nowMs)
nowMs = new Date().valueOf();
return true;
function drawLinesToHtmlCanvas()
// Get canvas and context here...
var drawSpeed = 500; // ms.
for (i=0; i<lines; i++)
// Draw lines to canvas...
while (!sleep(drawSpeed));
这个很慢,while循环等待合适的时间耗尽了所有浏览器资源,完全无法使用。此外,随着函数 drawLinesToHtmlCanvas()
的运行,线条不会更新到画布元素。
setTimeout()
的 promise 解决方案非常棒,只是不够精确,无法满足我的要求。
我可以做出类似于第一个示例的承诺吗?但不是使用setTimeout()
,而是使用与我的Date()
now 与 end ms 比较类似的算法,因为这样会更准确吗?
线条现在需要能够被绘制到 1 毫秒并具有实时更新,用户需要能够看到画在画布上的线条。
【问题讨论】:
显示器甚至不会刷新接近那么快的任何地方 解释器永远不允许setTimeout
在几毫秒之前安排回调(对于某些浏览器,最小值可能高达 12 毫秒),除非您将其传递为零(然后这甚至不是保证)。获得流畅动画的首选方法是使用回调调用requestAnimationFrame
。
setTimeout 甚至故意抖动(或确实)来对抗我认为的幽灵
@CertainPerformance 最终的函数将在屏幕上绘制数百万次,(想想从微小组件中缓慢构建的视觉数据)我考虑过批处理(例如,每毫秒 2000 个绘制事件) 但认为只是为每个绘制事件添加一个微小的延迟会更简单。
@Touffy 好吧,也许我一直走错路,我会看看 requestAnimationFrame
【参考方案1】:
即使setTimeout
确实在如此短的时间范围内工作,这也可能不会成功。当您使用回调和/或承诺时,您依赖于 JS 运行时的事件循环。这个事件循环只会尽可能快地执行你的回调。该架构将施加滞后,当您低于 1 毫秒时,这些滞后将变得可见。 setTimeout
中的回调在经过 N 毫秒后并未完全执行。经过 N ms 后,它才有资格被执行。只有在轮到另一个事件循环滴答时才会最终调用它。
至于您的第二种方法,它并不完全“用完资源”。问题是您不再使用事件循环。但是你必须记住,JS 是单线程的。并且正因为如此,当 JS 代码不停地执行时,它根本不会让用户与 UI 交互。用户只能在在事件回调执行之间做一些事情。因此,除非您想破坏用户体验,否则不要在浏览器中的 JS 中使用长时间运行的 while。也许除非您使用 Web Worker,因为它们可以让您创建新线程,但是您将无法从那里绘制任何内容。
一般而言,您对动画的处理方式是“画一些东西然后睡觉”是相当幼稚的。高性能和流畅的动画是视频卡的目的,尽管在浏览器中编写它以有效利用视频卡可能很棘手。如果你想在浏览器中制作动画,那么你必须找到专门为 Canvas 或 WebGL 上的动画制作的特定浏览器函数调用。 也许从这里开始: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations
还要考虑您是否真的需要每秒帧数。超过1000fps?显示器可以吗?性能影响如何?
【讨论】:
以上是关于如何在Javascript中制作精确的睡眠功能,可能使用承诺?的主要内容,如果未能解决你的问题,请参考以下文章
javascript / node.js中的睡眠功能[重复]
JavaScript 中是不是有睡眠/暂停/等待功能? [复制]