Search code examples
javascriptarraysiframedelaysleep

Javascript - Delay, Pause, Sleep -- WHERE ARE YOU? + Changing iFrame's SRC with Array


I'm having problems with setTimeout. I've also tried setInterval. I wish JS just had a pause or sleep.

In theory, this code should write the first link from the array, wait 3 seconds, write the next, and so on. But it won't even call the function.

<html>
<head></head>
<body>

<a href="http://www.google.com">Google</a>
<a href="http://www.thinkgeek.com">ThinkGeek</a>
<a href="http://www.themetapicture.com">The Meta Picture</a>

<iframe src="http://www.google.com" id="myid" name="main" width="1024" height="768">
</iframe>

<script>

function getLinksArray(){
for(var i=0; i < document.links.length; i++){
    var linx = document.links[i].href;
    setTimeout("openLinks(linx)"),3000);
}
}

function openLinks(link){
document.write(link + "<br />");
}

window.onload = getLinksArray();
</script>
</body>
</html>

The second part of my question is to change the src of the iframe to the links (instead of writing them). I'm only using the document.write for testing purposes to get the delay working.

I've tried document.getElementById("myid").src = link; and it won't do anything at all. Almost as if the iframe doesn't even exist.

I'm not a pro, so I'm here hoping to get help from a pro. ;) Thanks in advance.


Solution

  • First, never, ever, pass a string to setTimeout.

    // old and busted
    setTimeout("openLinks(linx)"),3000);
    
    // new hotness
    setTimeout(function() {
      openLinks(linx)
    }, 3000);
    

    Second, loops that generate functions need some additional help. You need to capture the value of the loop in a closure, otherwise the value will change before the function that uses it executes.

    function getLinksArray() {
        for (var i = 0; i < document.links.length; i++) {
            var linx = document.links[i].href;
    
            // create a closure for each loop iteration
            (function(linx) {
              setTimeout(function() {
                openLinks(linx);
              }, 3000);
            }(linx));
    
        }
    }
    
    function openLinks(link) {
        // document.write(link + "<br />");
    
        // document.write is also bad for a number of reasons
        someElement.innerHTML += link + "<br />"
    }
    
    window.onload = getLinksArray();
    

    What that closure magic does is create brand new local variable shared only with the function created on each iteration of the loop. Without it you actually have something that looks more like this:

    var linx; // var linx in the loop actually get hoisted to outside the loop!
    for(var i=0; i < document.links.length; i++){
        linx = document.links[i].href;
        setTimeout(function() {
          openLinks(linx)
        },3000);
      }
    }
    

    Looking at that, you can see that the loop will be done running, linx will be set the last value of that loop, and then your first timeout will fire using the value of linx that all the timeouts share.

    Creating and executing a function, passing in that value prevents that hoisting and sharing.