问题
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: Done";
found = 1;
break;
}
}
}
}
function doIndex(pg) {
b = document.getElementById('shouldi');
if (!is404 && b.checked === true) {
cstatus.innerHTML = "Status: 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: 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: 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): <input type="text" value="30" maxlength="3" size="3" id="timerbox"> </td><td style="width: 33%"> <center><font size="20" color="red" id="page"> </font></center> </td><td style="width: 33%;text-align:left;"> <span id="checkcheck"><label for="shouldi">Checking</label><input type="checkbox" id="shouldi" /></span> <span id="checkstatus">Status: </span></td></tr></tbody></table>';
main.parentNode.insertBefore(ui, main);
cstatus = document.getElementById('checkstatus');
cstatus.innerHTML = "Status: 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:
- Initially,
readyStateis not four, sofoundis false. Sincepgstarts at 0,doIndex(pg + 1)is called. Now,xhr1gets overwritten by a new XHR instance. - This continues, until
pgreaches 15. Then,pg < 15is false, and the horror starts:xhr1.onreadystatechangefires multiple time during the request.pg < 15is false, so theelseblock 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 createdxhr1request.
So, you're callingdoIndex(pg+1)over and over again, which, oncepghas 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);
}
}
};
来源:https://stackoverflow.com/questions/11064095/xmlhttprequest-launches-multiple-times-without-initiating-the-onreadystatechange