compose-iterator
Advanced tools
Comparing version 1.0.1 to 1.1.0
@@ -30,11 +30,2 @@ 'use strict' | ||
/** | ||
* Make an iterator for middleware. | ||
*/ | ||
middleware[Symbol.iterator] = iterator | ||
// Alternative iteration. | ||
const iter = middleware[Symbol.iterator]() | ||
/** | ||
* @param {Object} context | ||
@@ -46,4 +37,7 @@ * @return {Promise} | ||
return function (context, next) { | ||
// iteration object | ||
const iter = iterator[Symbol.iterator](middleware, context, next) | ||
try { | ||
return Promise.resolve(iter.next(context, next).value) | ||
return Promise.resolve(iter.next().value) | ||
} catch (err) { | ||
@@ -50,0 +44,0 @@ return Promise.reject(err) |
61
index.js
'use strict' | ||
/** | ||
* Expose iterator. | ||
*/ | ||
module.exports = iterator | ||
/** | ||
* Make an iterator for middleware. | ||
@@ -16,32 +10,29 @@ * | ||
function iterator () { | ||
const self = this | ||
const length = this.length | ||
let i = 0 | ||
let context | ||
let nextFunc | ||
const iterator = { | ||
[Symbol.iterator] (middleware, context, nextFunc) { | ||
const length = middleware.length | ||
let i = -1 | ||
return { | ||
next (c, n) { | ||
if (!context) context = c | ||
if (!nextFunc) nextFunc = n | ||
return { | ||
let fn = self[i++] || nextFunc | ||
let done = i > length | ||
let value | ||
let nextCalled = false | ||
next () { | ||
let fn = middleware[++i] || nextFunc | ||
let done = i === length | ||
let value | ||
let nextCalled = false | ||
if (fn) { | ||
value = fn(context, () => { | ||
if (nextCalled) { | ||
return Promise.reject(new Error('next() called multiple times')) | ||
} | ||
nextCalled = true | ||
return Promise.resolve().then(() => this.next().value) | ||
}) | ||
} | ||
if (fn) { | ||
value = fn(context, () => { | ||
if (nextCalled) { | ||
throw new Error('next() called multiple times') | ||
} | ||
nextCalled = true | ||
return Promise.resolve().then(() => this.next().value) | ||
}) | ||
} | ||
return { | ||
value, | ||
done | ||
return { | ||
value, | ||
done | ||
} | ||
} | ||
@@ -51,1 +42,7 @@ } | ||
} | ||
/** | ||
* Expose iterator. | ||
*/ | ||
module.exports = iterator |
{ | ||
"name": "compose-iterator", | ||
"version": "1.0.1", | ||
"version": "1.1.0", | ||
"description": "Fastest iterator for middleware composition", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
# Compose Iterator | ||
Fastest iterator for middleware composition. The biggest performance improvements for Koa middleware. | ||
Use iterator for middleware composition. | ||
## Benchmarks | ||
**For [koa-compose v3](https://github.com/koajs/compose/tree/3.1.0)**, https://github.com/koajs/compose/pull/57 | ||
### Before | ||
``` | ||
compose | ||
43,981 op/s » (fn * 1) | ||
25,044 op/s » (fn * 2) | ||
13,359 op/s » (fn * 4) | ||
6,972 op/s » (fn * 8) | ||
3,555 op/s » (fn * 16) | ||
1,803 op/s » (fn * 32) | ||
920 op/s » (fn * 64) | ||
466 op/s » (fn * 128) | ||
231 op/s » (fn * 256) | ||
113 op/s » (fn * 512) | ||
55 op/s » (fn * 1024) | ||
27 op/s » (fn * 2048) | ||
13 op/s » (fn * 4096) | ||
6 op/s » (fn * 8192) | ||
``` | ||
### After | ||
``` | ||
compose | ||
206,669 op/s » (fn * 1) | ||
202,517 op/s » (fn * 2) | ||
209,224 op/s » (fn * 4) | ||
208,893 op/s » (fn * 8) | ||
205,962 op/s » (fn * 16) | ||
205,885 op/s » (fn * 32) | ||
205,316 op/s » (fn * 64) | ||
206,602 op/s » (fn * 128) | ||
205,352 op/s » (fn * 256) | ||
201,229 op/s » (fn * 512) | ||
188,328 op/s » (fn * 1024) | ||
167,314 op/s » (fn * 2048) | ||
182,743 op/s » (fn * 4096) | ||
174,105 op/s » (fn * 8192) | ||
``` | ||
## Installation | ||
@@ -64,3 +20,3 @@ | ||
const iterator = require('compose-iterator') | ||
const iterator = require('..') | ||
@@ -90,11 +46,2 @@ /** | ||
/** | ||
* Make an iterator for middleware. | ||
*/ | ||
middleware[Symbol.iterator] = iterator | ||
// Alternative iteration. | ||
const iter = middleware[Symbol.iterator]() | ||
/** | ||
* @param {Object} context | ||
@@ -106,4 +53,7 @@ * @return {Promise} | ||
return function (context, next) { | ||
// iteration object | ||
const iter = iterator[Symbol.iterator](middleware, context, next) | ||
try { | ||
return Promise.resolve(iter.next(context, next).value) | ||
return Promise.resolve(iter.next().value) | ||
} catch (err) { | ||
@@ -110,0 +60,0 @@ return Promise.reject(err) |
@@ -47,2 +47,43 @@ 'use strict' | ||
it('should be able to be called twice', () => { | ||
var stack = [] | ||
stack.push(function * (context, next) { | ||
context.arr.push(1) | ||
yield wait(1) | ||
yield next() | ||
yield wait(1) | ||
context.arr.push(6) | ||
}) | ||
stack.push(function * (context, next) { | ||
context.arr.push(2) | ||
yield wait(1) | ||
yield next() | ||
yield wait(1) | ||
context.arr.push(5) | ||
}) | ||
stack.push(function * (context, next) { | ||
context.arr.push(3) | ||
yield wait(1) | ||
yield next() | ||
yield wait(1) | ||
context.arr.push(4) | ||
}) | ||
const fn = compose(stack.map((fn) => co.wrap(fn))) | ||
const ctx1 = { arr: [] } | ||
const ctx2 = { arr: [] } | ||
const out = [1, 2, 3, 4, 5, 6] | ||
return fn(ctx1).then(() => { | ||
assert.deepEqual(out, ctx1.arr) | ||
return fn(ctx2) | ||
}).then(() => { | ||
assert.deepEqual(out, ctx2.arr) | ||
}) | ||
}) | ||
it('should only accept an array', function () { | ||
@@ -260,2 +301,20 @@ var err | ||
}) | ||
it('should not affect the original middleware array', () => { | ||
const middleware = [] | ||
const fn1 = (ctx, next) => { | ||
return next() | ||
} | ||
middleware.push(fn1) | ||
for (const fn of middleware) { | ||
assert.equal(fn, fn1) | ||
} | ||
compose(middleware) | ||
for (const fn of middleware) { | ||
assert.equal(fn, fn1) | ||
} | ||
}) | ||
}) |
392
13970
116