Real-Time-Rate-Limiting-Queue

If more requests are made within the specified interval than the specified number, it waits until the oldest one is older than the interval before making the next request in the queue.

このスクリプトは単体で利用できません。右のようなメタデータを含むスクリプトから、ライブラリとして読み込まれます: // @require https://update.greasyfork.org/scripts/559799/1718888/Real-Time-Rate-Limiting-Queue.js

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

You will need to install an extension such as Tampermonkey to install this script.

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
作者
JasonMel
バージョン
1.0.0
作成日
2025/12/22
更新日
2025/12/22
大きさ
34.5KB
ライセンス
MIT https://mit-license.org/

Uses Mike Diarmid's Denque https://github.com/Salakar — copyright (c) 2018 Invertase Limited https://github.com/invertase/denque


Sometimes, a script may need to make many requests to a site. If the script makes enough requests in a short enough time, the site may consequently become annoyed at their server getting hammered. Some sites actually require scripts to limit requests to a published frequency or face consequences of some sort. This class allows you to automatically limit the frequency of requests that your script makes.

What makes this class special is that the rate is limited in real time, which all but guarantees that any given request will be made the moment the timeline of your past requests permits it, without, for example, waiting for a multiple of the interval to pass, or recomputing an equivalent rate based on a different interval.

This class requires some familiarity with the use of javascript Promises. A good primer is https://javascript.info/async.


To use, access

globalThis[meta]

where meta is a string key composed of the @required script's metadata @namespace, @name, and the major version number of @version, joined with colons. I.e.,

globalThis["github.com/JasonAMelancon:Real-Time-Rate-Limiting-Queue:1"]

In a script that @requires this script, the above expression will evaluate to the Real-time Rate-limiting Queue class, which can be assigned to a variable, which is then usable as the class identifier.

(Only the major version is used because updating the script changes the version number, which would break this mechanism, but a new major version would typically break including scripts anyway.)


All documentation is available as JSDoc comments. Where this excerpt of the JSDoc differs from that found in the code, prefer the latter.

constructor(reqPerInterval, interval, concurrent, array, dequeOptions)

Instantiates the queue.

reqPerInterval Requests per interval. The numerator of the queue rate parameter. Will be set to the default of 1 if not a valid positive number.

interval The denominator of the queue rate parameter in milliseconds. Will be set to the default of 0 if not a valid non-negative number. 0 disables rate limit.

concurrent Pass in false if each item should wait for the last to finish before executing. Only inherently asynchronous operations may be concurrent.

array Can be supplied if the desired item queue exists as an array already. Note that queue execution only begins on enqueueing an object.

dequeOptions Passed on to internal deque class, which currently ignores it. See Denque module (https://github.com/invertase/denque).

enqueue(item)

Enqueue the item object itself (not a copy).

item To be useful, this must have a function in its "executor" or "callback" property. This is the request whose rate of calling will be controlled. If supplied, the executor property must contain a function of the kind that Promise() takes. If there is a callback and no executor, the callback should return either a truthy value (which may be a result), or a falsy value indicating failure. In either case, the item will be given a "timestamp" property containing the javascript datetime of the request execution, a boolean "success" property, and a "promise" property containing a Promise, automatically constructed from the executor if supplied, holding the result of the request. Rejected Promises and failed callbacks will not count toward the rate limit. These should result from, for example, fetching an invalid URL or having no network, but not from a 404 Not Found, which would typically still count since it requires server time.

Returns a Promise that resolves to the supplied item once its promise property is settled. Do not confuse these two Promises! This one resolves to the enqueued item when its request is settled, while the Promise on the item itself contains the result of the request. This is in order to make the other information on the item available when the request result is accessed.

Here is a brief example of how an instance of the queue class, named myRtrlQueue, would be created and used in practice.

const Rtrlq = globalThis["github.com/JasonAMelancon:Real-Time-Rate-Limiting-Queue:1"];
const myRtrlQueue = new Rtrlq(3, Rtrlq.seconds(5)); // max of 3 requests every 5 seconds
const URL = "https://www.site.net/api/some/text/";
// ...
const queueItem = myRtrlQueue.enqueue({
                     executor: (resolve, reject) => fetch(URL).then(resolve, reject),
                     id: 69105
                  });
// ...
// now examine request result, along with any associated data you put on the queue item
queueItem.then(item => item.promise
    .then(response => {
        if (!response.ok) {
            throw new Error(`${response.status} - ${response.statusText}`);
        }
        console.log(`Queued request ${item.id} succeeded: ${response.body}`);
    })
    .catch(err => console.error(`Queued request ${item.id} failed: ${err}`)));