【发布时间】: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
标签: javascript asynchronous promise sleep nonblocking