为什么这个 Javascript setTimeout 和 setInterval 运行 进入竞争状态?

Why is this Javascript setTimeout and setInterval running into a race condition?

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 中似乎没有这个 t & s 会得到优化并且奇怪的事情发生了。

我对 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() 的时间间隔,当您的函数 fadeCarousel 被调用时,rotateCarousel 的时间间隔 调用 :) 这使得 fadeCarousel 调用比 interval insite fadeCarousel 函数调用更快。例如:

1: window.setInterval(rotateCarousel, 5000);// A 表示 5s 后 rotateCarousel 将调用。

2: fadeCarousel(activeChild, carouselinner, 500, 100); //B 500 毫秒后关闭。

but: when A make next call 表示在5s之后B已经在4.5s之前完成了。思考:在 A 调用 B 完成后 5000 - (n * 500ms) 那为什么 activeChild 比赛条件(我正在努力提高我的英语)如果你不明白请告诉我举个例子。