JS Why does the loop not support the same interval time?

I made a small slider to create three images, I want each image to stop for 3 seconds, then fadeOut and fadeIn in the next, but the problem is this: the
first can stay 3 seconds, but as soon as it starts to loop, it will not stop for 3 seconds, the image will immediately change, why can't it hold 3 seconds to stay?
Here is a demo

var i = 0;
var name = ['Cat', 'Dog', 'Duck'];

function next() {
  if (i > 1) {
    i = 0;
  } else {
    i++;
  };
  $('#loop').fadeOut(1000, function() {
    $(this).css('background', 'url("' + i + '.png")').fadeIn(1000);
    $('h1').html(name[i]);
  });
};
setInterval(next, 3000);
#loop {
  width: 300px;
  height: 300px;
  background: url('0.png');
}
h1 {
  padding-top: 310px;
  text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="loop">
  <h1>Cat</h1>
</div>
Run codeHide result
+4
source share
2 answers

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>Loop</title>
    <style type="text/css">
        #loop{
            width: 300px;
            height: 300px;
            background: url('0.png');
        }
        h1{
            padding-top: 310px;
            text-align: center;
        }
    </style>
</head>
<body>
<div id="loop">
    <h1>Cat</h1>
</div>


<script src="https://code.jquery.com/jquery-3.0.0.min.js"
        integrity="sha256-JmvOoLtYsmqlsWxa7mDSLMwa6dZ9rrIdtrrVYRnDRH0="
        crossorigin="anonymous">
</script>
<script>
    $(function (){
        var i = 0;
        var name = ['Cat', 'Dog', 'Duck'];

        var timerId = setTimeout(next, 3000);
        function next(){
            if (i > 1) {
                i = 0;
            }else{
                i++;
            };
            $('#loop').fadeOut(1000, function (){
                $(this).css('background', 'url("'+ i +'.png")').fadeIn(1000);
                $('h1').html(name[i]);
                timerId = setTimeout(next, 3000);
            });
        };

    });
</script>
</body>


</html>
Run codeHide result
+3
source

You can use the .queue(), .delay(), .promise(), recursion

$(function() {

var names = ['Cat', 'Dog', 'Duck'];

var images = ["http://placehold.it/300x300?text=Cat"
             , "http://placehold.it/300x300?text=Dog"
             , "http://placehold.it/300x300?text=Duck"]

function next() {
  return $("#loop")
    .queue("names", $.map(names, function(name, i) {
      return function(next) {
        $(this).css("background", "url(" + images[i] + ")")
        .find("h1").html(name).end()
        .fadeIn(1000, function() {
          $(this).delay(3000)
          .fadeOut(1000).promise().then(next)
        })
      }
    }))
    .dequeue("names").promise("names").then(next)
};

next();

})
#loop {
  width: 300px;
  height: 300px;
  background-repeat:no-repeat;
}
h1 {
  padding-top: 310px;
  text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="loop">
  <h1>Cat</h1>
</div>
Run codeHide result
+1

Source: https://habr.com/ru/post/1657901/