Question

I have code for a typewriter-like effect, where a paragraph is spelled out a letter at a time with a short time delay. It works by iterating through a for loop and appending each letter to the div. Here's the weird part: If you switch tabs or minimize Chrome while it is running, it messes up and prints gibberish, but if you stay on the tab where it is running, it works fine. In Firefox it works fine, no weirdness when you change tabs. What is going on? Here's my code:

$(function () {

var global_tw = "Well, the way they make shows is, they make one show. That show's called a pilot. Then they show that show to the people who make shows, and on the strength of that one show they decide if they're going to make more shows. Some pilots get picked and become television programs. Some don't, become nothing. She starred in one of the ones that became nothing.";
var codeWordsFlag = false;

function typewriter () { 
    var tw = global_tw.split('');

        for (i = 0; i <= tw.length; i++) {
            delayPrint(i);
        };


    function delayPrint(i) {
        setTimeout(function(){
            $('.codeWords').append(tw[i]);
        }, 75*i); //75
    };
    codeWordsFlag = true;
};
typewriter();
})

I should also mention that I tried "appending" using text() and html() (e.g., $('.codeWords').text($('.codeWords').text() + tw[i]);), and while that seemed to reduce the error rate in chrome, the bug still happened when you switched tabs/minimized.

Here's the fiddle (try it out and see what I mean): http://jsfiddle.net/Shambolaz/Xe56x/14/

Thanks for reading.

EDIT: Check Michael's answer for a solution to the problem of working around delayed timeout calls when Chrome was minimized.

Was it helpful?

Solution

The timeouts can be delayed when the tab is backgrounded, which is causing these to get executed out-of-order. A simple workaround is to always fire the next event from the previous one. That is, instead of:

for (var i = 0; i < tw.length; ++i) {
  delayPrint(i);
}

... instead do:

 delayPrint(tw, 0);

... with:

 function delayPrint(arr, index) {
   if (index >= arr.length) {
     return;
   }
   setTimeout(function() {
     printElement(arr[index]);
     delayPrint(arr, index+1);
   }, 75);
 }

 function printElement(str) {
   $('.codeWords').append(str);
 }

In both cases, you should be aware that the timing is not guaranteed to be even... if you want to make the animation look smooth, you should figure out how much time elapsed since the previous invocation, and use that to determine how many characters to print out on the current iteration.

OTHER TIPS

Try the use of jQuery promises to print out the letters. there fore each print will have to wait for the previous print to complete.

Now i think the issue is the browser is creating multiple print statements before the previous is completed and then randomly picks up a newly created print event to run.

Let me know if you need a code sample. :) :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top