您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Asynchronous function queue with adjustable concurrency.
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.icu/scripts/482311/1296526/queue.js
// queue v7.0.0 // Source Code: https://github.com/jessetane/queue/tree/7.0.0 // Licensed under MIT License const { QueueEvent, Queue } = (() => { const has = Object.prototype.hasOwnProperty /** * Since CustomEvent is only supported in nodejs since version 19, * you have to create your own class instead of using CustomEvent * @see https://github.com/nodejs/node/issues/40678 * */ class QueueEvent extends Event { constructor (name, detail) { super(name) this.detail = detail } } class Queue extends EventTarget { constructor (options = {}) { super() const { concurrency = Infinity, timeout = 0, autostart = false, results = null } = options this.concurrency = concurrency this.timeout = timeout this.autostart = autostart this.results = results this.pending = 0 this.session = 0 this.running = false this.jobs = [] this.timers = [] this.addEventListener('error', this._errorHandler) } _errorHandler (evt) { this.end(evt.detail.error) } pop () { return this.jobs.pop() } shift () { return this.jobs.shift() } indexOf (searchElement, fromIndex) { return this.jobs.indexOf(searchElement, fromIndex) } lastIndexOf (searchElement, fromIndex) { if (fromIndex !== undefined) return this.jobs.lastIndexOf(searchElement, fromIndex) return this.jobs.lastIndexOf(searchElement) } slice (start, end) { this.jobs = this.jobs.slice(start, end) return this } reverse () { this.jobs.reverse() return this } push (...workers) { const methodResult = this.jobs.push(...workers) if (this.autostart) this._start() return methodResult } unshift (...workers) { const methodResult = this.jobs.unshift(...workers) if (this.autostart) this._start() return methodResult } splice (start, deleteCount, ...workers) { this.jobs.splice(start, deleteCount, ...workers) if (this.autostart) this._start() return this } get length () { return this.pending + this.jobs.length } start (callback) { if (this.running) throw new Error('already started') let awaiter if (callback) { this._addCallbackToEndEvent(callback) } else { awaiter = this._createPromiseToEndEvent() } this._start() return awaiter } _start () { this.running = true if (this.pending >= this.concurrency) { return } if (this.jobs.length === 0) { if (this.pending === 0) { this.done() } return } const job = this.jobs.shift() const session = this.session const timeout = (job !== undefined) && has.call(job, 'timeout') ? job.timeout : this.timeout let once = true let timeoutId = null let didTimeout = false let resultIndex = null const next = (error, ...result) => { if (once && this.session === session) { once = false this.pending-- if (timeoutId !== null) { this.timers = this.timers.filter(tID => tID !== timeoutId) clearTimeout(timeoutId) } if (error) { this.dispatchEvent(new QueueEvent('error', { error, job })) } else if (!didTimeout) { if (resultIndex !== null && this.results !== null) { this.results[resultIndex] = [...result] } this.dispatchEvent(new QueueEvent('success', { result: [...result], job })) } if (this.session === session) { if (this.pending === 0 && this.jobs.length === 0) { this.done() } else if (this.running) { this._start() } } } } if (timeout) { timeoutId = setTimeout(() => { didTimeout = true this.dispatchEvent(new QueueEvent('timeout', { next, job })) next() }, timeout) this.timers.push(timeoutId) } if (this.results != null) { resultIndex = this.results.length this.results[resultIndex] = null } this.pending++ this.dispatchEvent(new QueueEvent('start', { job })) job.promise = job(next) if (job.promise !== undefined && typeof job.promise.then === 'function') { job.promise.then(function (result) { return next(undefined, result) }).catch(function (err) { return next(err || true) }) } if (this.running && this.jobs.length > 0) { this._start() } } stop () { this.running = false } end (error) { this.clearTimers() this.jobs.length = 0 this.pending = 0 this.done(error) } clearTimers () { this.timers.forEach(timer => { clearTimeout(timer) }) this.timers = [] } _addCallbackToEndEvent (cb) { const onend = evt => { this.removeEventListener('end', onend) cb(evt.detail.error, this.results) } this.addEventListener('end', onend) } _createPromiseToEndEvent () { return new Promise((resolve, reject) => { this._addCallbackToEndEvent((error, results) => { if (error) reject(error) else resolve(results) }) }) } done (error) { this.session++ this.running = false this.dispatchEvent(new QueueEvent('end', { error })) } } return { QueueEvent, Queue }; })();