timeInterval with nested timeOut

Viewed 96

after page loading I need:

  • wait 7 sec
  • aniwrap.text() - LOREM IPSUM
  • wait 7 sec
  • aniwrap.text() - DOLOR SIT
  • and so on - repeating the pause and changing the text

In my try - I have only the second text, without the first one

any help?

var i;
var txt = '';
var arra = ["LOREM IPSUM", "DOLOR SIT"];
var aniwrap = $('#aniwrap');

function write() {
  if (i < txt.length) {
    document.getElementById("aniwrap").innerHTML += txt.charAt(i);
    i++;
    setTimeout(write, 70);
  }
}

function single(){
    $(arra).each(function(el, val){
        setTimeout(function(){
            aniwrap.text('');
            i = 0;
            console.log(val);
            txt = val;
            write();
        }, 7000);
    });
}

$(window).on('load', function(){
    setInterval(single, 7000);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='aniwrap'></div>

3 Answers

You have a couple problems: $(element/selector).each(cb) is for jQuery objects, what you want for iteration over an array is $.each(array, cb) (or just array.forEach. The other problem is that you're creating the setTimeouts in the loop, at the same time). Unless I'm missing something you don't actually need the loop or setTimeout in single at all.

var idx = 0;
function single() {
  if (idx == arra.length) {
    idx = 0;
  }
  var val = arra[idx];
  aniwrap.text('');
  idx++;
  i = 0;
  txt = val;
  write();
}

Declare a variable that determines the index of the word in the arra array:

var index = 0;

I removed the each() method and did it in a different way:

function single(){
  setTimeout(function(){
    index++;
      ...
      txt = arra[index % arra.length];
      ...
  }, 7000);
}

var i;
var index = 0;
var txt = '';
var arra = ["LOREM IPSUM", "DOLOR SIT"];
var aniwrap = $('#aniwrap');

function write() {
  if (i < txt.length) {
    document.getElementById("aniwrap").innerHTML += txt.charAt(i);
    i++;
    setTimeout(write, 70);
  }
}

function single(){
  setTimeout(function(){
    index++;
      aniwrap.text('');
      i = 0;
      console.log(arra[index % arra.length]);
      txt = arra[index % arra.length];
      write();
  }, 7000);
}

$(window).on('load', function(){
    setInterval(single, 7000);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='aniwrap'></div>

Function single sets up two timer callbacks that will execute successively but more or less immediately one after the other (they are both use a 7000ms timer).

On the first timer callback i is set to 0 and txt to LOREM IPSUM, and write will output the first letter L.

Before a page refresh has a chance to occur (in most cases), the second timer call back executes, which clears the text content of #aniwrap, resets the character pointer i back to zero and replaces the text with DOLOR SIT.

Now write will continue to output DOLOR SIT one letter at a time, but because the timer created in the first call to write was never cancelled, at twice the letter rate anticipated.

This is a timing problem. One way of resolving it would be to set up a different time delay for each line in arra, with another choice being to use a single 7000ms timer to write a single line and then call itself back for the next line with a timer.

Here's an example of the first option with minimum modification of the posted code:

"use strict";
var i;
var txt = '';
var arra = ["LOREM IPSUM", "DOLOR SIT"];
var aniwrap = $('#aniwrap');

function write() {
  if (i < txt.length) {
    document.getElementById("aniwrap").innerHTML += txt.charAt(i);
    i++;
    setTimeout(write, 70);
  }
}

function single(){
    $(arra).each(function(index, val){  // argument name change
        setTimeout(function(){
            aniwrap.text('');
            i = 0;
            console.log(val);
            txt = val;
            write();
        }, 3500 * index);  // <-- change
    });
}

$(window).on('load', function(){
    setInterval(single, 7000);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='aniwrap'></div>

A third way of resolving the issue might be to put a fixed length pause between lines so they could be any length (timings reduced for this example):

"use strict";
var i;
let lineNum = -1;
var txt = '';
var arra = ["LOREM IPSUM", "DOLOR SIT", "GAUDEAMUS IGITUR"];
var aniwrap = $('#aniwrap');

function write() {
  console.log(txt);
  if (i < txt.length) {
    document.getElementById("aniwrap").innerHTML += txt.charAt(i);
    i++;
    setTimeout(write, 70);
  }
  else setTimeout( nextLine, 3500);
}

function nextLine(){
    lineNum = ++ lineNum % arra.length;
    txt = arra[ lineNum];
    aniwrap.text('');
    i = 0;
    write();
}
 
$(window).on('load', nextLine)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='aniwrap'></div>

Related