XMLHttpRequest launches multiple times without ini

2019-08-17 01:37发布

问题:

The userscript in question: http://userscripts.org/scripts/show/130532

After the site it's been made for has been updated to HTML5, I had to update the script. However, it's got a really big problem now. When I launch the script's main function that contains the XMLHttpRequest, it simply spams the console with these requests until the browser simply crashes.

Now, I looked around in both StackOverflow and in Google for anything that could help me, but there's nothing.

If you proceed to try the script, be careful, because it crashes the browser. Or at least, it does for me in FF 11.00

Code:

// ==UserScript==
// @name           Where my thread at
// @include        *//boards.4chan.org/*/res/*
// ==/UserScript==

(function () {
    "use strict";
    var board = document.location.href.match(/https?:\/\/boards\.4chan\.org\/[\w]+/i), threadNo = location.pathname.match(/\/res\/([\d]+)/i), main = document.getElementsByName("delform")[0], is404 = 0, ttt = null, b, c, num, timer, html, i, l, no, found, xhr1, xhr2, cstatus, ui, pg;

    function lookup(resp) {
        html = resp.match(/<div class="postContainer opContainer".*?<\/div>[^<]*?<\/div>/gi);
        if (html) {
            l = html.length;
            for (i = 0; i < l; i += i) {
                no = html[i].match(/<a href="res\/([\d]+)"/i)[1];
                if (threadNo[1] === no) {
                    document.getElementById('page').innerHTML = pg;
                    cstatus.innerHTML = "Status:&nbsp;Done";
                    found = 1;
                    break;
                }
            }
        }
    }

    function doIndex(pg) {
        b = document.getElementById('shouldi');
        if (!is404 && b.checked === true) {
            cstatus.innerHTML = "Status:&nbsp;Searching";
            c = document.getElementById('timerbox');
            num = parseInt(c.value, 10);
            if (num > 600) { timer = 600; }
            if (num < 30) { timer = 30; }
            if (isNaN(num)) {
                timer = 60;
                alert("Value entered is not a valid number! Defaulting to 60");
                c.value = "60";
            }
            if (!timer) { timer = num; }
            xhr1 = new XMLHttpRequest();
            xhr1.open("GET", board[0] + (0 === pg ? "" : "/" + pg), true);
            xhr1.setRequestHeader("Cache-Control", "no-cache");
            xhr1.onreadystatechange = function () {
                if (xhr1.readyState === 4) {
                    if (xhr1.status === 200) {
                        lookup(xhr1.responseText);
                    }
                }
                if (found) {
                    ttt = setTimeout(function () {
                        doIndex(0);
                    }, timer * 1000);
                } else {
                    if (pg < 15) {
                        doIndex(pg + 1);
                    } else {
                        cstatus.innerHTML = "Status:&nbsp;Really 404?";
                        xhr2 = new XMLHttpRequest();
                        xhr2.open("GET", board[0] + threadNo[0], true);
                        xhr2.setRequestHeader("Cache-Control", "no-cache");
                        xhr2.onreadystatechange = function () {
                            if (xhr2.readyState === 4) {
                                if (xhr2.status === 404) {
                                    cstatus.parentNode.removeChild(cstatus);
                                    document.getElementById('page').innerHTML = "404'd";
                                    is404 = 1;
                                } else {
                                    cstatus.innerHTML = "Status:&nbsp;Still alive";
                                    setTimeout(function () {
                                        doIndex(0);
                                    }, 1000);
                                }
                            }
                        };
                        xhr2.send(null);
                    }
                }
            };
            xhr1.send(null);
        }
    }

    ui = document.createElement('center');
    ui.innerHTML = '<table border="0" style="width: 100%"><tbody><tr><td style="width: 33%;text-align: right;">Timer(600-30s):&nbsp;<input type="text" value="30" maxlength="3" size="3" id="timerbox">&nbsp;&nbsp;</td><td style="width: 33%">&nbsp;<center><font size="20" color="red" id="page">&nbsp;</font></center>&nbsp;</td><td style="width: 33%;text-align:left;">&nbsp;&nbsp;<span id="checkcheck"><label for="shouldi">Checking</label><input type="checkbox" id="shouldi" /></span>&nbsp;&nbsp;<span id="checkstatus">Status:&nbsp;</span></td></tr></tbody></table>';
    main.parentNode.insertBefore(ui, main);
    cstatus = document.getElementById('checkstatus');
    cstatus.innerHTML = "Status:&nbsp;Ready";
    document.getElementById('checkcheck').addEventListener("click", function () {
        if (ttt !== null) {
            clearTimeout(ttt);
            ttt = null;
        }
        setTimeout(function () {
            doIndex(0);
        }, 500);
    }, false);
}());

回答1:

You're using several variables without declaring these locally:

var ..., found, xhr1, xhr2, cstatus, ui, pg;
...
function doIndex(pg) {
    ...
        xhr1 = new XMLHttpRequest();
     // ^^^^ No var !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        ...
        xhr1.onreadystatechange = function() {
            if (xhr1.readyState === 4) { ... }
            if (found) {
                ...
            } else {
                if (pg < 15) {
                    doIndex(pg + 1); // <-- !!!!!!!!!!!!!!!!!!
                } else { ...
                    xhr2 = new XMLHttpRequest();
                    ...
                    xhr2.onreadystatechange = function() { ... };
                    xhr2.send(null);
                }
            }
        };
        xhr1.send(null);
    }
}  ...
doIndex(0); // Initiate the doom

First, you assign a new XHR instance to a non-local xhr1 variable.
Then, you add a readystatechange event handler, in which the following happens:

  1. Initially, readyState is not four, so found is false. Since pg starts at 0, doIndex(pg + 1) is called. Now, xhr1 gets overwritten by a new XHR instance.
  2. This continues, until pg reaches 15. Then, pg < 15 is false, and the horror starts:
    • xhr1.onreadystatechange fires multiple time during the request. pg < 15 is false, so the else block is evaluated, in which you launch several new XHR (xhr2) requests...
    • All of the previous readystatechange events are still fired, because the requests haven't finished yet. In every event handler, you're comparing the value of xhr1.readyState, which refers to the state of the last created xhr1 request.
      So, you're calling doIndex(pg+1) over and over again, which, once pg has reached 15, creates new XHR (xhr2) instances.

To fix the problem, declare the variables in the function, and wrap the whole onreadystatechange block in if (xhr1.readyState == 4) (or use onload instead of onreadystatechange).

function dIndex(pg) {
    var xhr1, xhr2;
    ...
    xhr1.onreadystatechange = function() {
        if (xhr1.readyState === 4) {
           /* ... */
        }
    };
    ...


回答2:

This helped based on answers:

                    let signupRequest = new XMLHttpRequest();
                    let url = "signup/" + inputMobile.value;
                    signupRequest.open("GET", url, true);
                    signupRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
                    signupRequest.send();

                    signupRequest.onreadystatechange = function () {
                        if (signupRequest.readyState === 4) {
                            hideLoading();
                            if (signupRequest.status === 200) {
                                console.log("OK: " + status + " --- " + signupRequest.response);
                            } else {
                                console.log("NOK: " + status + " --- " + signupRequest.response);
                            }
                        }
                    };