RequestQueue

A simple queue for GM_xmlhttpRequests or other async functions

Este script no debería instalarse directamente. Es una biblioteca que utilizan otros scripts mediante la meta-directiva de inclusión // @require https://update.greasyfork.org/scripts/370011/610040/RequestQueue.js

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==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
    __result : 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.__result = 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: result = thisArg.fun(req)
    // it will call result.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].__result.abort === 'function') {
        running[i].__result.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;
  }
  
  
}