🏠 Home 

RequestQueue

A simple queue for GM_xmlhttpRequests or other async functions

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.greasyfork.org/scripts/370011/610040/RequestQueue.js

// ==UserScript==
// @exclude     *
// ==UserLibrary==
// @name        RequestQueue
// @description A simple queue for GM_xmlhttpRequests or other async functions
// @version     6
// @license     MIT
// ==/UserLibrary==
// @namespace   cuzi
// @homepageURL https://github.com/cvzi/RequestQueue/
// @grant       GM_xmlhttpRequest
// @grant       GM.xmlhttpRequest
// ==/UserScript==
// ==OpenUserJS==
// @author      cuzi
// ==/OpenUserJS==
"use strict";
function RequestQueue(maxParallel,maxTotal) {
// A simple queue for GM_xmlhttpRequests or other async functions
maxParallel = parseInt(maxParallel)>0?parseInt(maxParallel):1;
maxTotal = parseInt(maxTotal)>0?parseInt(maxTotal):Number.POSITIVE_INFINITY;
var index = 0; // incrementing, used for unique ids
var finished = 0; // Number of finished requests
var pending = [];
var running = [];
var defaultFunction;
if(typeof GM != "undefined" && "xmlHttpRequest" in GM) {
defaultFunction = GM.xmlHttpRequest;
} else {
defaultFunction = function(a,b,c,d) { return GM_xmlhttpRequest(a,b,c,d);} // Wrap GM_xmlhttpRequest to avoid security exception
}
/*
The internal request Object extended by add(req,fun,thisArg)
{
__fun : fun, defaults to GM_xmlhttpRequest
__thisArg : thisArg, the this object for the above function
__r###lt : the return value of __fun is saved in this property
__org_onload : The original event callbacks of req
__org_onerror
__org_onabort
onload : The new event callbacks that wrap the above callbacks
onerror
onabort
... and all the original properties of the "req" object
}
*/
var fire = function() {
// Check for pending requests and send them.
if(pending.length > 0 && running.length < maxParallel && finished < maxTotal) {
var req = pending.shift();
running.push(req);
req.__r###lt = req.__fun.call(req.__thisArg,req);
fire();
}
};
var remove = function(id) {
// Remove the request with id from the the running array
for(var i = 0; i < running.length; i++) {
if(running[i].id == id) {
running.splice(i, 1);
finished++;
fire();
break;
}
}
};
this.add = function(req,fun,thisArg) {
// Schedule a request: add(req[, fun[, thisArg]])
// fun:      defaults to GM.xmlHttpRequest
// thisArg:  The value of this provided for the call to fun. Keep strict mode in mind!
req.id = index++;
req.__fun = typeof(fun) === 'function'?fun:defaultFunction;
req.__thisArg = thisArg;
// Wrap events that indicate that the request has finished
req.__org_onload = req.onload;
req.onload = function(response) {
if(response.status === 0) { // This is true if a request was aborted. This seems to happen only sporadically
req.onabort(response);
return;
}
remove(req.id);
if(req.__org_onload) req.__org_onload(response);
};
req.__org_onerror = req.onerror;
req.onerror = function(response) {
remove(req.id);
if(req.__org_onerror) req.__org_onerror(response);
};
req.__org_onabort = req.onabort;
req.onabort = function(response) {
remove(req.id);
if(req.__org_onabort) req.__org_onabort(response);
};
pending.push(req);
fire();
};
this.abortRunning = function() {
// For any added function that was already run: r###lt = thisArg.fun(req)
// it will call r###lt.abort()
// For GM_xmlhttpRequest this will subsequently fire an onabort event
for(var i = 0; i < running.length; i++) {
if(running[i] && typeof running[i].__r###lt.abort === 'function') {
running[i].__r###lt.abort();
}
}
};
this.abortPending = function() {
// Clear the pending list
pending = [];
};
this.abort = function() {
// Abort both running and pending requests
this.abortPending();
this.abortRunning();
};
this.resetTotal = function() {
// Reset number of finished requests
finished = 0;
}
this.hasReachedTotal = function() {
// Number of maximum allowed requests reached?
return finished >= maxTotal;
}
this.hasRunning = function() {
// Are there any running requests?
return running.length > 0;
}
}