简体   繁体   中英

JavaScript: setTimeout in loop still doesn't work

I needed to create a script, which is sending post requests (data in array) continuously to server and getting responses, but I also need to make delays (for about 3-5 seconds) between every 5th or 6th iteration. As example:

1st data
2nd data
3rd data
4th data
5th data
** 5sec. delay - wait here**
6th data
7th data
...etc...

Sending and receiving data is OK, but I can't correctly implement setTimeout in my code to be fully working as I need.

Big thanks to everyone, who will be able to fix this code.

<!DOCTYPE html>
<html>
<body>

<h2>AJAX</h2>

<button type="button" onclick="loadDoc()">Request data</button>

<p id="demo"></p>

<script>
function loadDoc() {
    var xhttp = [];



    var code = [
"WOICEL0Q9P",
"ZJTS4GYJEJ",
"HJPMQOCX31",
"MP26N0BH01",
"7TJNYZIRJR",
"Z5MIDDG4N2",
"BX6MKYK0O7",
"KVFVH1ESQX",
"40ADY3ZBE5",
"V4NT360JR5",
"FDI8AFL680",
"ZH89N59XQR",
"M6OS2OX38H",
"D8O76YDLM0",
"86GBMJLIXY",
"1QRFVU26VK",
"HFUI9QV6DY",
"VN83OGR825",
"DDMPCBX2MF",
"2M3QFPI234"
    ];

    var i = code.length;
    var j = code.length;
    var k = 5000;

    var p = 0;


    while (i--) {
        var process = (function(i) {
            if (p == 5) {
                p = 0;
                function func(i) {
                    xhttp[i] = new XMLHttpRequest();
                    xhttp[i].onreadystatechange = function() {
                        if (xhttp[i].readyState == 4 && xhttp[i].status == 200) {
                            if (i == j) {
                                document.getElementById("demo").innerHTML = code[i] + ":   " + xhttp[i].responseText;
                            }
                            else {
                                document.getElementById("demo").innerHTML += "<br><br>" + code[i] + ":   " + xhttp[i].responseText;
                            }
                        }
                    };
                    xhttp[i].open("POST", "https://www.example.com/services/postdata.svc", true);
                    xhttp[i].setRequestHeader("Host", "www.example.com");
                    xhttp[i].setRequestHeader("Accept", "application/json, text/javascript");
                    xhttp[i].setRequestHeader("Accept-Language", "cs,en-US;q=0.7,en;q=0.3");
                    xhttp[i].setRequestHeader("Accept-Encoding", "gzip, deflate, br");
                    xhttp[i].setRequestHeader("Content-Type", "application/json; charset=utf-8");
                    xhttp[i].setRequestHeader("Cache-Control", "no-cache");
                    xhttp[i].setRequestHeader("X-Requested-With", "XMLHttpRequest");
                    xhttp[i].setRequestHeader("Referer", "https://www.example.com/postdata-test.htm");
                    xhttp[i].setRequestHeader("Content-Length", "37");
                    xhttp[i].setRequestHeader("Connection", "keep-alive");
                    xhttp[i].send('{"code":"'+code[i]+'","confirm":false}');
                    //console.log('hello - Test if delay is here');
                    p++;
                }
                setTimeout(func(i), k);
                k += 5000;
            }
            else {
                xhttp[i] = new XMLHttpRequest();
                xhttp[i].onreadystatechange = function() {
                    if (xhttp[i].readyState == 4 && xhttp[i].status == 200) {
                        if (i == j) {
                            document.getElementById("demo").innerHTML = code[i] + ":   " + xhttp[i].responseText;
                        }
                        else {
                            document.getElementById("demo").innerHTML += "<br><br>" + code[i] + ":   " + xhttp[i].responseText;
                        }
                    }
                };
                xhttp[i].open("POST", "https://www.example.com/services/postdata.svc", true);
                xhttp[i].setRequestHeader("Host", "www.example.com");
                xhttp[i].setRequestHeader("Accept", "application/json, text/javascript");
                xhttp[i].setRequestHeader("Accept-Language", "cs,en-US;q=0.7,en;q=0.3");
                xhttp[i].setRequestHeader("Accept-Encoding", "gzip, deflate, br");
                xhttp[i].setRequestHeader("Content-Type", "application/json; charset=utf-8");
                xhttp[i].setRequestHeader("Cache-Control", "no-cache");
                xhttp[i].setRequestHeader("X-Requested-With", "XMLHttpRequest");
                xhttp[i].setRequestHeader("Referer", "https://www.example.com/postdata-test.htm");
                xhttp[i].setRequestHeader("Content-Length", "37");
                xhttp[i].setRequestHeader("Connection", "keep-alive");
                xhttp[i].send('{"code":"'+code[i]+'","confirm":false}');
                p++;
            }
        })(i);
    }
}
</script>

</body>
</html>

You probably want to use setInterval() or you have to recursivly call setTimeout()

(function func() {
    //do your upload
    setTimeout(func, 3);
})();

with bind you can pass parameters:

(function func(i) {
    //do your upload
    setTimeout(func.bind(this, i), 3);
})();

This is a fully working example. See the comments and watch the log output to understand how it ticks, it's pretty self-explanatory.

<!DOCTYPE html>
<html>
    <body>
        <h2>AJAX</h2>
        <button type="button" onclick="loadDoc()">Request data</button>
        <p id="demo">Loading...</p>
        <script>
            function loadDoc() {

                var code = [
                    "WOICEL0Q9P",
                    "ZJTS4GYJEJ",
                    "HJPMQOCX31",
                    "MP26N0BH01",
                    "7TJNYZIRJR",
                    "Z5MIDDG4N2",
                    "BX6MKYK0O7",
                    "KVFVH1ESQX",
                    "40ADY3ZBE5",
                    "V4NT360JR5",
                    "FDI8AFL680",
                    "ZH89N59XQR",
                    "M6OS2OX38H",
                    "D8O76YDLM0",
                    "86GBMJLIXY",
                    "1QRFVU26VK",
                    "HFUI9QV6DY",
                    "VN83OGR825",
                    "DDMPCBX2MF",
                    "2M3QFPI234"
                ];
                var i = code.length;

                var pendingRequests = 0; // how many requests are waiting for a response\
                var htmlBuffer = []; // best practice to build your html before inserting to save memory

                // instead of using the closure inside the loop, just use a regular function
                // this way you're not duplicating the code and you're keeping the logic clean
                var makeRequest = function(i){
                    console.log("making a request");
                    var xhttp = new XMLHttpRequest();
                    xhttp.onreadystatechange = function () {                
                        if (xhttp.readyState == 4 && xhttp.status == 200) {

                            //. add to the buffer
                            htmlBuffer.push(code[i]+":   "+xhttp.responseText);
                            pendingRequests--;
                            console.log("request is back. "+pendingRequests+" requests still pending.");


                            if(pendingRequests===0){
                                // if there are no pending requests
                                if(i==0){
                                    // if there are no more codes to send, put the thml in the dom
                                    document.getElementById("demo").innerHTML = htmlBuffer.join('<br>');
                                }else{
                                    // else wait 3 seconds and send the next 5 requests
                                    console.log("waiting 3 seconds... "+i+" codes still need to be sent.");
                                    setTimeout(doFiveRequests, 3000);
                                }
                            }
                        }
                    };
                    xhttp.open("POST", "https://www.example.com/services/postdata.svc", true);
                    xhttp.setRequestHeader("Host", "www.example.com");
                    xhttp.setRequestHeader("Accept", "application/json, text/javascript");
                    xhttp.setRequestHeader("Accept-Language", "cs,en-US;q=0.7,en;q=0.3");
                    xhttp.setRequestHeader("Accept-Encoding", "gzip, deflate, br");
                    xhttp.setRequestHeader("Content-Type", "application/json; charset=utf-8");
                    xhttp.setRequestHeader("Cache-Control", "no-cache");
                    xhttp.setRequestHeader("X-Requested-With", "XMLHttpRequest");
                    xhttp.setRequestHeader("Referer", "https://www.example.com/postdata-test.htm");
                    xhttp.setRequestHeader("Content-Length", "37");
                    xhttp.setRequestHeader("Connection", "keep-alive");
                    xhttp.send('{"code":"' + code[i] + '","confirm":false}');
                    pendingRequests++;
                };

                // this function just calls the next 5 requests
                var doFiveRequests = function(){
                    // make next 5 requests
                    for(var n=i-5; i>n&&i>-1; i--){
                        makeRequest(i);
                    }
                };

                // start the loop...
                doFiveRequests();

            } // end function
        </script>
    </body>
</html>

This is because of the way you are calling your are calling the setTimeout function

By calling the setTimeout function in the following way

setTimeout(func(i), k);

You are actually assigning the result of funct(i) as the callback for your setTimeout

you should call the setTimeout like so

setTimeout(func.bind(this, i), k);

Which will call the func function with the current this context bound to it, with the current i variable

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM