我最近尝试学习网页设计,并希望用JavaScript做一个简单的图像淡出。我知道jQuery有一种更简单的方法,经过一段时间后我就用这种方式解决了这个问题,但是我偶然发现它并且想要解释为什么会发生这种情况。
要打破这个过程,我可以说我有一个图像,希望它每0.1秒减少一次不透明度。因此我使用for循环并使用SetTimeout(淡入淡出,100)调用淡入淡出函数。但是10个循环中的每个循环都是同时执行的。我用
尝试了更简单setTimeout(fade,100);
setTimeout(fade,100); ....
即使这样,所有10个函数实例也会立即执行。 因此,对于未来的项目:为什么会这样,是否有可能的解决方法?
非常感谢
答案 0 :(得分:2)
你应该使用setInterval。
setInterval(fade,100);
setInterval用于重复性任务。它会继续运行。一旦完成,请确保清除间隔以防止内存泄漏。
您正在使用for循环,这不是正确的方法。
假设当前时间是:0
您运行了for循环并创建了5个setTimeouts。创建它需要一些时间,但你无法注意到它。
因此,每个setTimeout应在100 ms后执行。
但它们是在:
创建的 1. 0.000000001
2. 0.000000002
3. 0.000000003
4. 0.000000004
5. 0.000000005
他们将在以下情况后调用回调:
1. 100.000000001
2. 100.000000002
3. 100.000000003
4. 100.000000004
5. 100.000000005
(仅供演示)
所以,你不会注意到它们,而这些(setTimeout和setInterval)不是绝对的。他们需要更长时间。
希望它有所帮助。 :d
答案 1 :(得分:0)
答案是event loop
。要彻底了解此行为,您必须了解事件循环的所有阶段,尤其是如何处理setTimeout
和setInterval
关于事件循环的MDN文章 MDN event loop
上升的堆栈文章将帮助您清楚地了解事件循环以及微观和宏观任务
rising stack event loop explained
简而言之,所有setTimeout
都在循环的tick
处理。
同样适合您的情况setInterval
要好得多
答案 2 :(得分:0)
有多种方法可以实现它。正如其他人所建议您可以使用setTimeout
或使用for
来递归调用。如果由于某种原因必须使用setTimeout
循环,那也是可能的。
基本思路是,您必须在第一次执行fade
函数后才能调用第二个setTimeout
,否则会增加连续调用//\//\//\// method 1
function fadeRecur() {
var d1 = document.querySelector( ".d1" );
if(d1.style.opacity == '') d1.style.opacity = 1;
//console.log(d1.style.opacity);
if(d1.style.opacity > 0) {
d1.style.opacity -= 0.1;
setTimeout(fadeRecur, 100);
}
}
setTimeout(fadeRecur, 100);
//\//\//\// method 2
var fsi;
function fadeInter() {
var d2 = document.querySelector( ".d2" );
if(d2.style.opacity == '') d2.style.opacity = 1;
// console.log(d2.style.opacity);
if(d2.style.opacity > 0) {
d2.style.opacity -= 0.1;
} else {
clearInterval(fsi);
}
}
fsi = setInterval(fadeInter, 100);
//\//\//\// method 3
function fadeLoop() {
var d3 = document.querySelector( ".d3" );
if(d3.style.opacity == '') d3.style.opacity = 1;
//console.log(d3.style.opacity);
if(d3.style.opacity > 0) {
d3.style.opacity -= 0.1;
}
}
for(var i=1; i<=10; i++) {
setTimeout(fadeLoop, i*100);
}
之间的超时时间。
.d1 {
background-color: rgba(255, 0, 0, 0.5);
}
.d2 {
background-color: rgba(0, 255, 0, 0.5);
}
.d3 {
background-color: rgba(0, 0, 255, 0.5);
}
<div class='d1'>recursive setTimeout</div>
<div class='d2'>single setInterval</div>
<div class='d3'>setTimeout in for loop</div>
.dropdown-menu { position: fixed; }
答案 3 :(得分:0)
如果您想使用setTimeout每100毫秒更改一次不透明度,可以试试这个
setTimeout(fade,100);
setTimeout(fade,200);
setTimeout(fade,300);
...
或在循环中设置时序变量
for(let timing=100,timeing<1000,timing+=100) setTimeout(fade,timing);
10 setTimeout函数几乎同时启动,每100ms触发一次,直到1000ms。因为它是异步函数,所以它不会等待先前的命令完成。