3

It may be a little confusing :S

If anyone can help me to split an array of strings into letters. And than to tape it with time-outs. Like in DOS.

I can do this with single strings, but i can't do it in arrays.

Here is my code:

var text = new Array();
text[0] = "welcome ".split('');
text[1] = "how are u?".split('');
var delay = 20;
for (var j = 0; j < text.length; j++) {

    var txt = text[j];
    for (u = 0; u < txt.length; u++) {
        setTimeout(function () {
            $('div#console_div').append('<br />' + txt.shift());
        }, delay * j + 100);
    }
}
Cerbrus
  • 70,800
  • 18
  • 132
  • 147
Ilir V. Gruda
  • 1,562
  • 5
  • 17
  • 23

2 Answers2

3

This is how I would do it. Instead of a for loop, use a recursive function which calls itself with different arguments depending on where it is on the string(s):

var text = new Array();
text[0] = "welcome ".split('');
text[1] = "how are you?".split('');
var delay = 400;

function addOneChar(i, j) {
    $('#console_div').append('<br>' + text[i][j]);
    if (j+1<text[i].length) {  // next character in the current string
        setTimeout(function() { addOneChar(i, j+1); }, delay);
    } else if (i+1<text.length) {   // start the next string in the text[] array
        setTimeout(function() { addOneChar(i+1, 0); }, delay);
    } // else quit
}

setTimeout(function() { addOneChar(0,0); });

http://jsfiddle.net/mblase75/tkEDN/

We could simplify this further by combining text[] into a single string and using .charAt() to extract characters:

var text = new Array();
text[0] = "welcome ";
text[1] = "how are you?";
var delay = 400;
var textstr = text.join('');

function addOneChar(i) {
    $('#console_div').append('<br>' + textstr.charAt(i));
    if (i+1<textstr.length) {
        setTimeout(function() { addOneChar(i+1); }, delay);
    } // else quit
}

setTimeout(function() { addOneChar(0); });

http://jsfiddle.net/mblase75/MYtjy/

Blazemonger
  • 90,923
  • 26
  • 142
  • 180
3

You have the typical "closure in a loop" problem. Have a look at JavaScript closure inside loops – simple practical example. At the moment the timeout callbacks are executed, txt refers to text[1]. All the timeouts are still executed though, so you are calling txt.shift() more often than there are elements in the array.

Another problem is that any delay up to 100ms is hardly noticeable by any human being, so you don't see any increment. Even worse, for the first phrase, all timeouts are executed at the same time (nearly), since j is 0 and delay * j + 100 will result in 100.


You are better off processing each letter one by one instead of creating all the timeouts at once (note that Blazemonger's solution is the same, but easier to understand since it is cleaner).

var text = [...];

function printLetter(phrase_index, letter_index) {
    var word = text[phrase_index];
    if (word) {
        if (letter_index === word.length) {
            printLetter(phrase_index + 1, 0);
        }
        else {
            var letter = word[letter_index];
            if (letter) {
                $('div#console_div').append('<br />' + letter);
                setTimeout(function() {
                    printLetter(phrase_index, letter_index + 1);
                }, 200);
            }
        }
    }
}

printLetter(0, 0);

DEMO

Community
  • 1
  • 1
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143