【问题标题】:XMLHttpRequest launches multiple times without initiating the onreadystatechange functionXMLHttpRequest 多次启动而不启动 onreadystatechange 函数
【发布时间】:2012-06-16 14:05:05
【问题描述】:

有问题的用户脚本:http://userscripts.org/scripts/show/130532

在创建它的网站更新为 HTML5 后,我不得不更新脚本。然而,它现在有一个非常大的问题。当我启动包含 XMLHttpRequest 的脚本主函数时,它只是向控制台发送这些请求,直到浏览器崩溃为止。

现在,我在 StackOverflow 和 Google 中寻找任何可以帮助我的东西,但什么都没有。

如果您继续尝试该脚本,请小心,因为它会使浏览器崩溃。或者至少,它在 FF 11.00 中对我有用

代码:

// ==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);
}());

【问题讨论】:

  • @BrockAdams OP 是该脚本的作者(参见 Gravatar)。但是,代码必须包含在问题中,因为可以删除用户脚本,使这个问题对未来的访问者毫无用处。
  • @RobW,好眼力(否则 OP 入侵了可怜的 KittyAwesome 的帐户;))。你是对的,应该包含代码,但这个问题似乎仍然不太可能帮助任何人,除了 OP。
  • 我不打算删除这个用户脚本,所以不用担心。此外,userscripts.org 有版本历史。

标签: javascript xmlhttprequest userscripts


【解决方案1】:

您使用多个变量没有声明这些本地

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

首先,您将一个新的 XHR 实例分配给一个非本地的 xhr1 变量。
然后,添加一个readystatechange 事件处理程序,其中会发生以下情况:

  1. 最初,readyState 不是四个,所以found 是假的。由于 pg 从 0 开始,所以调用了 doIndex(pg + 1)。现在,xhr1 被新的 XHR 实例覆盖
  2. 这样继续,直到pg 达到 15。然后,pg &lt; 15 为假,恐怖开始:
    • xhr1.onreadystatechange 在请求期间多次触发。 pg &lt; 15 为 false,因此会评估 else 块,您可以在其中启动几个新的 XHR (xhr2) 请求...
    • 所有之前的 readystatechange 事件仍然被触发,因为请求还没有完成。在每个事件处理程序中,您都在比较 xhr1.readyState 的值,它指的是最后创建的 xhr1 请求的状态
      因此,您一遍又一遍地调用doIndex(pg+1),一旦pg 达到15,就会创建新的XHR (xhr2) 实例。

要解决此问题,请在函数中声明变量,并将整个 onreadystatechange 块包装在 if (xhr1.readyState == 4) 中(或使用 onload 而不是 onreadystatechange)。

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

【讨论】:

  • 好吧,我玩过你说的那些东西,但不知何故,它们都没有按预期工作。我终于放弃了,回到了早期的版本并更新了它。它现在也不能正常工作,因为当我勾选复选框时,它会在第一页上触发 XMLHttpRequest 两次。如果您有任何想法,请随时在脚本的讨论页面中写下。
【解决方案2】:

这有助于基于答案:

                    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);
                            }
                        }
                    };

【讨论】:

    猜你喜欢
    • 2012-12-27
    • 2011-05-29
    • 1970-01-01
    • 2018-01-01
    • 1970-01-01
    • 2021-11-29
    • 2020-03-08
    • 2017-11-23
    • 1970-01-01
    相关资源
    最近更新 更多