Trouble using setTimeout function

2019-07-18 15:04发布

问题:

I've never been able to properly use the setTimeout function, so I tried writing a sample script to update a progress bar, but again, it does not work. Instead, the entire program runs before the progress bar is updated to 100%. Would somebody be able to look at this code and tell me what I'm doing wrong?

The code I'm trying to use is from http://digitalbush.com/projects/progress-bar-plugin/

Thanks!

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<script language="javascript" type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script src="http://digitalbush.com/wp-content/uploads/2007/02/jqueryprogressbar.js" type="text/javascript"></script>
<title>Progress Bar test</title>
</head>
<body>
<style>
    /* progress bar container */
    #progressbar{
        border:1px solid black;
        width:200px;
        height:20px;
        position:relative;
        color:black; 
    }
    /* color bar */
    #progressbar div.progress{
        position:absolute;
        width:0;
        height:100%;
        overflow:hidden;
        background-color:#369;
    }
    /* text on bar */
    #progressbar div.progress .text{
        position:absolute;
        text-align:center;
        color:white;
    }
    /* text off bar */
    #progressbar div.text{
        position:absolute;
        width:100%;
        height:100%;
        text-align:center;
    }
</style>

<div id="progressbar"></div>
<input type='button' value='start' onClick='run()' />

<script>
function run() {
    for (i=0; i<100; i++) {
        setTimeout( function() {
            $("#progressbar").reportprogress(i);
        }, 500);
    }
}
</script>
</body>
</html>

回答1:

The issue is that variable i becomes the part of the closure and, when the function is executed, is already equal to 100.

The code you have currently literally creates a hundred of timeouts referencing the same variable(global i). By the time all of the functions are executed, i equals 100, therefore you report 100 as current progress 100 times.

The proper version should look like that:

function run() {
    var i = 0;
    setTimeout( function updateProgress() {
        $("#progressbar").reportprogress(i++);
        if (i < 100){
            setTimeout(updateProgress, 500);
        }
    }, 500);
}

You could check closures part of javascript garden for explanation and possible other solutions.



回答2:

setTimeout is not sleep (JavaScript doesn't have a sleep).

As you loop round, you set the function to run in 500ms, then you immediately set it to run again in 500ms, and so on. So effectively, you set it to run 100 times in 500ms, and have set i to 100 before the first time it executes (since it takes a JS engine less then half a second to run that for loop 100 times).

You want something more like this:

var interval, i = 0;
interval = setInterval(function () {
    if (i === 100) {
        clearInterval(interval);
    } else {
        $("#progressbar").reportprogress(i);
        i++;
    }
}, 500);