Hal_9100 Hal_9100 - 1 year ago 58
Javascript Question

function calling itself with setInterval (browser freezing issue)

I know there already are similar questions to mine but none of the answers I read solved my problem.

I wrote a small script that prints a string letter by letter using two functions : first one spells the string, second one calls the first using

setInterval
as long as the word isn't entirely spelled :

function write() {
writeThis = str.substring(0, currentLetter);
div.innerHTML = writeThis;
currentLetter++;
console.log('running');
}

function start() {
setInterval(function() {
if (currentLetter > str.length) {
return false;
}
write(); //calls the writing function
}, 100);
}
start();


I need to merge these two functions into one in order to dynamically use it on different strings by passing the strings as a parameter. I'm trying to do something like this :

function write(thisString) {
//code
return thisString;
}
var str1 = "hello world";
var str2 = "foo bar";
write(str1); write(str2);


I'm stuck when it comes to insert
setInterval
in
write()
function to call itself. No matter what I try
write()
will just call itself forever (despite the
if
condition) and freeze the browser. Is it possible to merge these two functions into one ?

Demo here : https://jsfiddle.net/Hal_9100/b5gm8nbc/

Answer Source

setInterval will keep firing until you call clearInterval(intervalId).

For most animation, it's easier to control with setTimeout in any case, as follows:

var div = document.getElementById('div');
var str = 'hello world.';
var currentLetter = 1;

var writeThis = str.substring(0, currentLetter);

function write() {
    writeThis = str.substring(0, currentLetter);
    div.innerHTML = writeThis;
    currentLetter++;
    console.log('running'); 
}

function run(){
    if (currentLetter > str.length) {
        return false;
    }
    write();
    setTimeout(run, 100);
}

function start() {
  setTimeout(run, 100);
}
start();

If you really want to use setInterval, the function returns the intervalId you need, so you'd do something like:

var intervalId = setInterval(fn, 100);

then in the if statement, you'd call

clearInterval(intervalId);

Obviously, you need to make sure intervalId is in scope in both places.

** EDIT **

Adding making it one function. Sorry I missed that part of the question. The trick here is to use Function.bind()

var div = document.getElementById('div');
var str = 'hello world.';
var currentLetter = 1;

var writeThis = str.substring(0, currentLetter);

function run(text){
    if (currentLetter > text.length) {
        return false;
    }
    writeThis = text.substring(0, currentLetter);
    div.innerHTML = writeThis;
    currentLetter++;
    console.log('running');
    setTimeout(run.bind(null, text), 100);
}

run(str);

If you wanted to pass in everything (e.g. the div, the str, the current letter), just add them as params to the run function and add them when you bind again.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download