Skip to content

Instantly share code, notes, and snippets.

@divinity76
Last active July 23, 2021 04:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save divinity76/20fb4c119f60859b6c8d881f09ff0b25 to your computer and use it in GitHub Desktop.
Save divinity76/20fb4c119f60859b6c8d881f09ff0b25 to your computer and use it in GitHub Desktop.
userland-queue for XMLHttpRequest for dealing with >=1400 concurrent requests (this makes 1400 concurrent requests stable on Chrome. Firefox doesn't have a problem with it)
function XMLHttpRequestWithUserlandQueue() {
if (!XMLHttpRequestWithUserlandQueue._master_internal) {
XMLHttpRequestWithUserlandQueue._master_internal = {
"max_concurrent": 100, // warning, while changing this number at runtime *might work*, i have not carefully coded to make sure that it actually *does* work to change this at runtime.
"process_queues": function () {
while (this.xhrs_ready_to_fire_queue.length > 0 && this.xhrs_running_queue.running_count() < this.max_concurrent) {
let to_fire = this.xhrs_ready_to_fire_queue.pop();
let realXHR = new XMLHttpRequest();
let realXHR_key = this.xhrs_running_queue.add(realXHR);
realXHR._XMLHttpRequestWithUserlandQueue_key = realXHR_key;
let endcb = function () {
for(let index in realXHR){
to_fire[index] = realXHR[index];
}
XMLHttpRequestWithUserlandQueue._master_internal.xhrs_running_queue.remove(realXHR_key);
XMLHttpRequestWithUserlandQueue._master_internal.process_queues();
};
realXHR.addEventListener("load", endcb);
realXHR.addEventListener("error", endcb);
for (let index in to_fire._local_internal["function_call_queue"]) {
let func_data = to_fire._local_internal["function_call_queue"][index];
// todo: to handle the situation where this stuff throws exception, we should probably re-write it to do
// some finally{} stuff to fire all the xhrs even when some of them throws exceptions.
// cba looking into it now...
// realXHR[func_data.function].apply(func_data.original_this, func_data.arguments);
realXHR[func_data.function].apply(realXHR, func_data.arguments);
}
};
},
"xhrs_ready_to_fire_queue": [],
"xhrs_running_queue": {
"key_counter": -1, // << will this key counter fail sometime after Number.MAX_SAFE_INTEGER / 9007199254740991 members? yes, in theory. in practice it should never be reached though..
"add": function (xhr) {
++this["key_counter"];
this[this["key_counter"]] = xhr;
return this["key_counter"];
},
"remove": function (keyToRemove) {
delete this[keyToRemove];
},
"running_count": function () {
let ret = 0;
for (let index in this) {
if (["key_counter", "add", "remove", "running_count"].indexOf(index) !== -1) {
continue;
}
++ret;
}
return ret;
}
}
};
}
const createObject = function (o) {
// i have no idea what im doing, just following https://stackoverflow.com/a/1919670/1067003
function XMLHttpRequestWithUserlandQueue() { }
XMLHttpRequestWithUserlandQueue.prototype = o;
return new XMLHttpRequestWithUserlandQueue();
};
let _internal = XMLHttpRequestWithUserlandQueue._internal;
let ret = createObject(XMLHttpRequestWithUserlandQueue.prototype);
ret._local_internal = {
"function_call_queue": [],
"fire_status": -1 // -1: not ready to fire. 0: ready to fire, but not fired yet. 1: fired
};
ret.open = function (method, url, async, user, password) {
if (async === undefined) {
async = true;
arguments[2] = true; // ..ick
}
if (!async) {
throw new Error("this userland hack doesnt support non-async..");
}
ret._local_internal["function_call_queue"].push({
"function": "open",
"original_this": this,
"arguments": arguments
});
};
ret.addEventListener = function () {
ret._local_internal["function_call_queue"].push({
"function": "addEventListener",
"original_this": this,
"arguments": arguments
});
};
ret.send = function () {
ret._local_internal["function_call_queue"].push({
"function": "send",
"original_this": this,
"arguments": arguments
});
ret._local_internal.fire_status = 0;
XMLHttpRequestWithUserlandQueue._master_internal.xhrs_ready_to_fire_queue.push(ret);
XMLHttpRequestWithUserlandQueue._master_internal.process_queues();
};
return ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment