为什么这个 Javascript setTimeout 和 setInterval 会遇到竞争条件?



document.addEventListener("DOMContentLoaded", function(event) {
	window.setInterval(rotateCarousel, 5000);
});
function fadeCarousel(n, e, t, s){
	var carousel = window.setInterval(function(){
		console.log(t/s);
			if (e.children[n].style.opacity>0){
				e.children[n].style.opacity = String(parseFloat(e.children[n].style.opacity) - .01);
			}
			
			if (e.children[(n+1) % e.childElementCount].style.opacity <1){
				e.children[(n+1) % e.childElementCount].style.opacity = String(parseFloat(e.children[(n+1) % e.childElementCount].style.opacity) + .01);
			}
	}, t/s);
	
	window.setTimeout(function(){
		clearInterval(carousel);
	},t);
};
function rotateCarousel(){
	var carouselinner = document.getElementsByClassName("carousel-inner")[0];
	var activeChild = 0;
	
	for (i=0; i< carouselinner.childElementCount; i++){
		if (carouselinner.children[i].classList.contains("active")){
			activeChild=i;
			i=carouselinner.childElementCount;
		}
	}
	
	fadeCarousel(activeChild, carouselinner, 500, 100);
	carouselinner.children[activeChild].classList.remove("active");
	carouselinner.children[(activeChild+1) % carouselinner.childElementCount].classList.add("active");
};
.carousel { 
z-index: -100; 
} /* keeps this behind all content */
.carousel .item {
	top:0;
	left:0;
position: fixed; 
width: 100%; 
	height: 100%;
	background-position: center;
}
.carousel .one {
		background-color:green;
		background-size: cover;
	}
	.carousel .two {
		background-color:blue;
		background-size: cover;
	}
	.carousel .three {
		background-color:yellow;
		background-size: cover;
	}
	.carousel .four {
		background-color: red;
		background-size: cover;
	}
<div id="BackgroundCarousel" class="carousel container slide">
<div class="carousel-inner">
<div class="item one active" style="opacity: 1;"></div>
<div class="item two" style="opacity: 0;"></div>
<div class="item three" style="opacity: 0;"></div>
<div class="item four" style="opacity: 0;"></div>
</div>
</div>

以上是我遇到的一个例子。

我想做的是让背景的透明度在设定的时间间隔内旋转进出,所以我使用setInterval调用一个函数rotateCarousel,该函数将div标记为显示的div 并调用过渡。

在更改时,我想有一个淡入淡出过渡,所以我有一个函数fadeCarousel,它将在短时间内调整两个相邻背景div 的不透明度。 由于我希望div 的淡入淡出停止,因此我以延迟清除setTimeout中的淡入淡出setInterval,这应该允许setInterval中的所有内容都完成。

似乎当我使用精确的值来清除间隔的延迟时,浏览器没有足够的时间来完成setInterval淡入淡出,并且当setTimeout运行clearInterval时,有时淡入淡出的setInterval是不完整的。 这让我的背景看起来卡在过渡中。

我试图通过提供大约 5 倍的延迟来解决这个问题,因为调用clearInterval应该需要延迟,但有时它似乎仍然存在问题(没有很大的余量,它似乎每次都有竞争条件)。 我也有console.log打印出来的t/s因为在Firefox中,似乎没有这个ts就会被优化,奇怪的事情正在发生。

我对setIntervalsetTimeout不了解 - 为什么这里有竞争条件?

因为当您更改活动元素时您的 for 循环是错误的,所以您的间隔未完成。 这就是为什么当下一个元素处于活动状态时,您的间隔已清除。 和您的竞争条件。我已经修复了此代码,我尝试在清除前向元素间隔后调用设置间隔下一个元素。查看截取的代码

var activeChild = -1;
document.addEventListener("DOMContentLoaded", function(event) {
	rotateCarousel();
});
function fadeCarousel(n, e, t, s){
	var carousel = window.setInterval(function(){
		  console.log(t/s);
			if (e.children[n].style.opacity>0){
				e.children[n].style.opacity = String(parseFloat(e.children[n].style.opacity) - .01);
			}
			
			if (e.children[(n+1) % e.childElementCount].style.opacity <1){
				e.children[(n+1) % e.childElementCount].style.opacity = String(parseFloat(e.children[(n+1) % e.childElementCount].style.opacity) + .01);
			}
	}, t/s);
	window.setTimeout(function(){
console.log("clear");
		clearInterval(carousel);
rotateCarousel();
	},t);	
};
function rotateCarousel(){
activeChild+=1;
	var carouselinner = document.getElementsByClassName("carousel-inner")[0];
if(carouselinner.childElementCount <= activeChild){
activeChild = 0;
}
console.log("element: " + activeChild);	
if(activeChild > 0){
carouselinner.children[activeChild - 1].classList.remove("active");
}
	carouselinner.children[activeChild].classList.add("active");
fadeCarousel(activeChild, carouselinner, 3000, 1000);

};
.carousel { 
z-index: -100; 
} /* keeps this behind all content */
.carousel .item {
	top:0;
	left:0;
position: fixed; 
width: 100%; 
	height: 100%;
	background-position: center;
}
.carousel .one {
		background-color:green;
		background-size: cover;
	}
	.carousel .two {
		background-color:blue;
		background-size: cover;
	}
	.carousel .three {
		background-color:yellow;
		background-size: cover;
	}
	.carousel .four {
		background-color: red;
		background-size: cover;
	}
<div id="BackgroundCarousel" class="carousel container slide">
<div class="carousel-inner">
<div class="item one" style="opacity: 1;"></div>
<div class="item two active" style="opacity: 0;"></div>
<div class="item three" style="opacity: 0;"></div>
<div class="item four" style="opacity: 0;"></div>
</div>
</div>

您的代码设置了调用rotateCarousel()的间隔,当您的函数淡出轮播调用时,调用的旋转轮播间隔:)这使得淡轮播调用比间隔式现场淡入淡出轮播功能更快。前任:

1: window.setInterval(rotateCarousel, 5000);//5s 旋转后 Carousel 将调用。

2:褪色轮播(activeChild,carouselinner,500,100); 关闭500ms后//B

但是:当A进行下一次调用时表示在 5s 之后B已经完成了 4.5s 之前。想一想:在 A拨打电话B完成 5000 - (n * 500ms) 之后,为什么activeChild比赛条件(我正在努力改进我的 Eng)如果你不明白,请告诉我举个例子。

最新更新