Search code examples
javascriptjquerysettimeout

why my nested setTimeout delay not working?


When i scroll on my "frame-2" element, i wanted to change the words every 300ms. the word change every 300ms and stop on each word of my array.

The scroll function works. The stop on each word also works but the delay is not of 300ms isn't respected and word change almost instantly. Do you see a mistake that I do not see ?

function interval(func, wait, times){
    var interv = function(w, t){
      return function(){
        if(typeof t === "undefined" || t-- > 0){
          setTimeout(interv, w);
          try{
            func.call(null);
          }
          catch(e){
            t = 0;
            throw e.toString();
          }
        }
      };
    }(wait, times);

    setTimeout(interv, wait);
  };

  var words21 = ["communication.", "image.", "concept.", "référencement.", "stratégie.", "contenu.", "social média."];
  var text21 = "repensent votre <span class='surlignement-rouge-text'>communication.</span>";
  var i21;
  var wi21;

  function _getChangedText21() {
    i21 = (i21 + 1);
    if (words21[i21] != undefined) {
      return text21.replace(/communication./, words21[i21]);
    } else {
      return text21.replace(/communication./, words21[wi21]);
      wi21 = (wi21 + 1);
    }
  }

  $(window).scroll(function() {
    text21.replace(/communication./, words21[0]);
    i21 = 0;
    wi21 = 1;
    x = 0;
    var hT20 = $('#frame-2').offset().top,
        hH20 = $('#frame-2').outerHeight(),
        wH20 = $(window).height(),
        wS20 = $(this).scrollTop();

    if (wS20 > (hT20+hH20-wH20)) {
      interval(function _getInterval21() {
        interval(function _changeText21() {
          var txt21 = _getChangedText21();
          document.getElementById("changer2").innerHTML = txt21;
        }, 300, 8);
        selectwords21 = words21[0];
        words21.shift();
        words21.push(selectwords21);
      }, 2000, 6);
      selectwords21 = words21[0];
      words21.shift();
      words21.push(selectwords21);
      selectwords21 = words21[0];
      words21.shift();
      words21.push(selectwords21);
    }
  });

Thx a lot, BadWoo

Edit : here is a codepen exemple : https://codepen.io/BadWoo/pen/MWyQbPB


Solution

  • If all you're trying to do is change the text inside changer2 for a rotating list of words in place of "communication." you could do this in a few lines of code (See example below).

    • No need to keep shifting and pushing words -- just use modulo operator %
    • No need to have nested calls to a setTimout - use setInterval

    Assuming I've understood correctly what you're trying to achieve here's the working code (adjust the timing as desired):

    function changeWords(){
    
      var words = ["communication.", "image.", "concept.", "référencement.", "stratégie.", "contenu.", "social média."];
      var i = 1;
      setInterval( () => {
        document.querySelector('.surlignement-rouge-text').innerHTML = words[i++ % words.length];
      }, 1000);
    
    }
    
    // You could call this from your scroll handler!
    changeWords();
    .surlignement-rouge-text{
        color: red
    }
    <span id="changer2">repensent votre <span class='surlignement-rouge-text'>communication.</span></span>

    Having further understood your requirement, it seems the code does need to be a little more complex but not much!

    var words = ["communication.", "image.", "concept.", "référencement.", "stratégie.", "contenu.", "social média."];
    
    async function changeWords(interval){
    
      return new Promise( resolve => {
      
        var i = 0;
        var timer = setInterval( () => {
          document.querySelector('.surlignement-rouge-text').innerHTML = words[i++];
          if(i == words.length){
            clearInterval(timer);
            resolve();
          }
        }, interval);
      });
    }
    
    async function cycleWords(shortInterval, longInterval, i){
      await changeWords(shortInterval);
      document.querySelector('.surlignement-rouge-text').innerHTML = words[i % words.length];
      setTimeout(() => cycleWords(shortInterval,longInterval, i+1),longInterval);
    }
    
    // You could call this from your scroll handler!
    cycleWords(300,2000,0);
    .surlignement-rouge-text{
        color: red
    }
    <span id="changer2">repensent votre <span class='surlignement-rouge-text'>communication.</span></span>