在不冻结浏览器的情况下在 setInterval 中休眠
Sleep inside of setInterval without freezing the browser
我有一个名为 "loop" 的函数,该函数正在使用 setInterval() 重复调用。在该函数内部,我需要另一个必须称为 "delay()" 的函数(它必须是确切的语法)。
所以我得到了这个:
function loop() {
console.log("some code")
delay(100)
console.log("some more code")
delay(100)
}
if (typeof loop != "undefined")
window.loopInterval = setInterval(loop, 1)
function delay(millis) {
var now = Date.now();
while(Date.now() < now + millis){}
}
这工作得很好,但它会冻结浏览器,使其无法正确呈现某些更改。
现在有什么方法可以更改延迟函数,以便它只是暂时暂停 setInterval?
正如我所说,循环和延迟函数的语法必须保持不变。是的,我有充分的理由。
对于所有不相信我的人,我确实有一个很好的理由,在这里:https://github.com/T-vK/LedStripSimulator
为 Arduinos 编写的代码几乎总是使用 loop() 函数,而 delay() 在 Arduinos 上也是很常见的事情,因为他们通常一次只做一件事。而一个以尽可能准确地复制Arduino语法为目的的JS模拟器当然需要同步延迟功能。
编辑:Here is a complete project I've been working on that easily demonstrates that it works.
我想通了......我只需要 运行 我的代码在一个单独的线程中。在那个线程中我可以睡一整天并且 DOM 渲染不会受到影响。
(浏览器必须支持网络工作者)
//Code that runs in a separate thread:
var blob = new Blob([`
function loop() {
console.log("some code");
delay(1000);
console.log("some more code");
delay(1000);
}
function delay(millis) {
var now = Date.now();
while(Date.now() < now + millis){} ;
}
if (typeof loop != "undefined")
setInterval(loop, 1);
`], { type: "text/javascript" });
var worker = new Worker(window.URL.createObjectURL(blob));
//Code that runs in the UI thread:
var text = 'This text will be added to this div letter by letter without any freezing from the delay() function.';
var currentLetter = 0;
var maxLetter = text.length-1;
var div = document.getElementById('lagFree');
setInterval(function() {
div.innerHTML = div.innerHTML + text[currentLetter];
if (currentLetter >= maxLetter) {
div.innerHTML = '';
currentLetter = 0;
} else
currentLetter++;
},10);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<div id="lagFree"></div>
</body>
</html>
正如您在控制台中看到的那样,它一次又一次地打印 "some code" 和 "some more code",中间有 1000 毫秒的同步延迟。即使我们这样做了,UI 也不会冻结并且文本动画 运行 很流畅。
我有一个名为 "loop" 的函数,该函数正在使用 setInterval() 重复调用。在该函数内部,我需要另一个必须称为 "delay()" 的函数(它必须是确切的语法)。
所以我得到了这个:
function loop() {
console.log("some code")
delay(100)
console.log("some more code")
delay(100)
}
if (typeof loop != "undefined")
window.loopInterval = setInterval(loop, 1)
function delay(millis) {
var now = Date.now();
while(Date.now() < now + millis){}
}
这工作得很好,但它会冻结浏览器,使其无法正确呈现某些更改。
现在有什么方法可以更改延迟函数,以便它只是暂时暂停 setInterval?
正如我所说,循环和延迟函数的语法必须保持不变。是的,我有充分的理由。
对于所有不相信我的人,我确实有一个很好的理由,在这里:https://github.com/T-vK/LedStripSimulator
为 Arduinos 编写的代码几乎总是使用 loop() 函数,而 delay() 在 Arduinos 上也是很常见的事情,因为他们通常一次只做一件事。而一个以尽可能准确地复制Arduino语法为目的的JS模拟器当然需要同步延迟功能。
编辑:Here is a complete project I've been working on that easily demonstrates that it works.
我想通了......我只需要 运行 我的代码在一个单独的线程中。在那个线程中我可以睡一整天并且 DOM 渲染不会受到影响。
(浏览器必须支持网络工作者)
//Code that runs in a separate thread:
var blob = new Blob([`
function loop() {
console.log("some code");
delay(1000);
console.log("some more code");
delay(1000);
}
function delay(millis) {
var now = Date.now();
while(Date.now() < now + millis){} ;
}
if (typeof loop != "undefined")
setInterval(loop, 1);
`], { type: "text/javascript" });
var worker = new Worker(window.URL.createObjectURL(blob));
//Code that runs in the UI thread:
var text = 'This text will be added to this div letter by letter without any freezing from the delay() function.';
var currentLetter = 0;
var maxLetter = text.length-1;
var div = document.getElementById('lagFree');
setInterval(function() {
div.innerHTML = div.innerHTML + text[currentLetter];
if (currentLetter >= maxLetter) {
div.innerHTML = '';
currentLetter = 0;
} else
currentLetter++;
},10);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<div id="lagFree"></div>
</body>
</html>
正如您在控制台中看到的那样,它一次又一次地打印 "some code" 和 "some more code",中间有 1000 毫秒的同步延迟。即使我们这样做了,UI 也不会冻结并且文本动画 运行 很流畅。