From b8b1e902ed07cf03f6756d4d078742537d966f27 Mon Sep 17 00:00:00 2001 From: Hossam Magdy Date: Sun, 3 May 2020 17:09:39 +0200 Subject: [PATCH 1/5] refactor(Limiter): use ES6 syntax --- index.js | 111 ++++++++++++++++++++++++------------------- test/throttleSpec.js | 2 +- 2 files changed, 62 insertions(+), 51 deletions(-) diff --git a/index.js b/index.js index d5c8a38..812dfa8 100644 --- a/index.js +++ b/index.js @@ -1,64 +1,75 @@ 'use strict'; -function Queue(options) { - if (!(this instanceof Queue)) { - return new Queue(options); - } +class Queue { + constructor(options) { + this.concurrency = (options || {}).concurrency || Infinity; + this.pending = 0; - options = options || {}; - this.concurrency = options.concurrency || Infinity; - this.pending = 0; - this.jobs = []; - this.onDoneCbs = []; - this._done = done.bind(this); - this._run = run.bind(this); -} + this.jobs = []; + this.onDoneCbs = []; -// Called upon completion of a job. Calls run() again -// to pluck the next job off the queue, if it exists. -function done() { - this.pending--; - this._run(); -} + this.push = this._extendFromArray('push'); + this.splice = this._extendFromArray('splice'); + this.unshift = this._extendFromArray('unshift'); -function run() { - // Do we have capacity for jobs? - // If so, start them, uip to the concurrency limit - while (this.pending < this.concurrency && this.jobs.length) { - this.pending++; - var job = this.jobs.shift(); - job(this._done); + this._run = this._run.bind(this); + this._done = this._done.bind(this); } - // Are we done processing all jobs? If so, call onDone callbacks - while (this.length === 0 && this.onDoneCbs.length) { - var cb = this.onDoneCbs.pop(); - cb(); + get length() { + return this.pending + this.jobs.length; } -} -// Replicate popular array methods to queue up jobs. -['push', 'splice', 'unshift'].forEach(function(method) { - Queue.prototype[method] = function() { - var methodResult = Array.prototype[method].apply(this.jobs, arguments); - process.nextTick(this._run); - return methodResult; - }; -}); + /** + * Called upon completion of a job. Calls _run() again + * to pluck the next job off the queue, if it exists. + */ + _done() { + this.pending--; + this._run(); + } -Object.defineProperty(Queue.prototype, 'length', { - get: function() { - return this.pending + this.jobs.length; + /** @private */ + _run() { + // Do we have capacity for jobs? + // If so, start them, uip to the concurrency limit + while (this.pending < this.concurrency && this.jobs.length) { + this.pending++; + const job = this.jobs.shift(); + job && job(this._done); + } + + // Are we done processing all jobs? If so, call onDone callbacks + while (this.length === 0 && this.onDoneCbs.length) { + var cb = this.onDoneCbs.pop(); + cb && cb(); + } + } + + /** + * Replicate popular array methods to queue up jobs. + */ + _extendFromArray(method) { + return function() { + // @ts-ignore + const methodResult = Array.prototype[method].apply(this.jobs, arguments); + // @ts-ignore + process.nextTick(this._run); + return methodResult; + }; } -}); -// Simply adds a callback to the end of the job list -Queue.prototype.onDone = function(cb) { - if (typeof cb === 'function') this.onDoneCbs.push(cb); - // If there are no jobs in the queue, this will call `cb()` in the next tick. - // This is intended for that there is predictable behavior even when running a - // job list of length 0. - process.nextTick(this._run); -}; + /** + * Simply adds a callback to the end of the job list + */ + onDone(cb) { + if (typeof cb === 'function') this.onDoneCbs.push(cb); + // If there are no jobs in the queue, this will call `cb()` in the next tick. + // This is intended for that there is predictable behavior even when running a + // job list of length 0. + // @ts-ignore + process.nextTick(this._run); + } +} module.exports = Queue; diff --git a/test/throttleSpec.js b/test/throttleSpec.js index a74657d..dcd2a61 100644 --- a/test/throttleSpec.js +++ b/test/throttleSpec.js @@ -153,7 +153,7 @@ describe('Async-Limiter', function(endTest) { }); it('has a length property that follows concurrency', function(endTest) { - var t = Limiter({ concurrency: 1 }); + var t = new Limiter({ concurrency: 1 }); t.push(function(cb) { setTimeout(function() { From 83dfe0e4bd832959c9cc2679d239bbb62de6ddba Mon Sep 17 00:00:00 2001 From: Hossam Magdy Date: Sun, 3 May 2020 20:42:51 +0200 Subject: [PATCH 2/5] chore(Limiter): add JSDoc --- index.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/index.js b/index.js index 812dfa8..1da7063 100644 --- a/index.js +++ b/index.js @@ -1,11 +1,27 @@ 'use strict'; +/** + * @typedef {() => void} LimiterCallback + * @typedef {(cb: LimiterCallback) => void | any} AsyncJobCallback + * @typedef {(...args: any) => any} OnDoneCallback + * + * @extends Array + */ class Queue { + /** + * @param {{ concurrency: number; }} [options={ concurrency: Infinity }] + */ constructor(options) { + /** @readonly @type {number} */ this.concurrency = (options || {}).concurrency || Infinity; + + /** @private @type {number} */ this.pending = 0; + /** @private @type {AsyncJobCallback[]} */ this.jobs = []; + + /** @private @type {OnDoneCallback[]} */ this.onDoneCbs = []; this.push = this._extendFromArray('push'); @@ -23,6 +39,7 @@ class Queue { /** * Called upon completion of a job. Calls _run() again * to pluck the next job off the queue, if it exists. + * @private */ _done() { this.pending--; @@ -48,6 +65,8 @@ class Queue { /** * Replicate popular array methods to queue up jobs. + * @private + * @param {string} method */ _extendFromArray(method) { return function() { @@ -61,6 +80,7 @@ class Queue { /** * Simply adds a callback to the end of the job list + * @param {any} cb */ onDone(cb) { if (typeof cb === 'function') this.onDoneCbs.push(cb); From 55609761295b1b3e9af61553bb02185c1c9e6e7c Mon Sep 17 00:00:00 2001 From: Hossam Magdy Date: Sun, 3 May 2020 22:06:01 +0200 Subject: [PATCH 3/5] feat(TS): support TS, add TypeScript declaration file --- index.d.ts | 15 +++++++++++++++ package.json | 2 ++ 2 files changed, 17 insertions(+) create mode 100644 index.d.ts diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..664fb1f --- /dev/null +++ b/index.d.ts @@ -0,0 +1,15 @@ +type LimiterCallback = () => void; +type AsyncJobCallback = (cb: LimiterCallback) => void | any; +type OnDoneCallback = (...args: any) => any; + +declare class Queue { + constructor(options?: {concurrency?: number}); + readonly length: number; + push(...items: AsyncJobCallback[]): number; + splice(start: number, deleteCount?: number): AsyncJobCallback[]; + splice(start: number, deleteCount: number, ...items: AsyncJobCallback[]): AsyncJobCallback[]; + unshift(...items: AsyncJobCallback[]): number; + onDone(cb: OnDoneCallback): void; +} + +export default Queue; diff --git a/package.json b/package.json index 37033dc..89a7c1c 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,8 @@ "example": "node example", "lint": "eslint ." }, + "main": "index.js", + "types": "index.d.ts", "repository": "https://github.com/strml/async-limiter.git", "author": "Samuel Reed Date: Sun, 3 May 2020 22:07:42 +0200 Subject: [PATCH 4/5] chore(pkg): include only necessary files in pkg previously included: - .travis.yml - .nycrc - .eslintignore see: https://docs.npmjs.com/files/package.json#files --- .npmignore | 9 --------- package.json | 4 ++++ 2 files changed, 4 insertions(+), 9 deletions(-) delete mode 100644 .npmignore diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 158f8f1..0000000 --- a/.npmignore +++ /dev/null @@ -1,9 +0,0 @@ -node_modules -coverage -test -example -.eslintrc.yaml -package-lock.json -yarn.lock -coverage -.nyc_output \ No newline at end of file diff --git a/package.json b/package.json index 89a7c1c..be5e471 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,10 @@ "example": "node example", "lint": "eslint ." }, + "files": [ + "index.js", + "index.d.ts" + ], "main": "index.js", "types": "index.d.ts", "repository": "https://github.com/strml/async-limiter.git", From dcdc5958582c698267340a518b7a71e80aa26b60 Mon Sep 17 00:00:00 2001 From: Hossam Magdy Date: Sun, 3 May 2020 22:57:56 +0200 Subject: [PATCH 5/5] fix(build): break comment to multiple lines --- index.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 1da7063..55065e0 100644 --- a/index.js +++ b/index.js @@ -84,9 +84,10 @@ class Queue { */ onDone(cb) { if (typeof cb === 'function') this.onDoneCbs.push(cb); - // If there are no jobs in the queue, this will call `cb()` in the next tick. - // This is intended for that there is predictable behavior even when running a - // job list of length 0. + // If there are no jobs in the queue, + // this will call `cb()` in the next tick. + // This is intended for that there is predictable + // behavior even when running a job list of length 0. // @ts-ignore process.nextTick(this._run); }