Skip to content

Instantly share code, notes, and snippets.

@norfish
Last active August 19, 2018 11:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save norfish/183fc75958a8f4ebc7a3a78d3564d78d to your computer and use it in GitHub Desktop.
Save norfish/183fc75958a8f4ebc7a3a78d3564d78d to your computer and use it in GitHub Desktop.
middleware_edit from koa
class Middleware {
constructor() {
this._middleware = []
}
use(...fns) {
fns.forEach(fn => {
if (typeof fn !== 'function') {
throw new TypeError('Middleware must be function!')
}
this._middleware.push(fn)
})
return this
}
compose(middleware) {
if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
for (const fn of middleware) {
if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
}
return function _compose(state, next) {
// last called middleware #
let index = -1
return dispatch(0)
function dispatch(i) {
if (i <= index) return Promise.reject(new Error('next() called multiple times'))
index = i
let fn = middleware[i]
if (i === middleware.length) fn = next
if (!fn) return Promise.resolve(state)
try {
return Promise.resolve(fn(state, dispatch.bind(null, i + 1)));
} catch (err) {
return Promise.reject(err)
}
}
}
}
async start(state) {
const fn = this.compose(this._middleware)
await fn(state)
}
}
// test run middleware
async function test() {
const reducer = new Middleware()
const state = {
count: 1
}
const m2 = a => {
console.log(a)
return async (state, next) => {
console.log('millde func')
await next()
}
}
reducer.use(m2('func'))
reducer.use(async (state, next) => {
state.name = 'm'
console.log('middle before 1')
await next()
})
reducer.use(async (state, next) => {
const p = new Promise(resolve => {
setTimeout(() => {
state.count++
console.log('settimeout')
resolve(state)
}, 100)
})
console.log('middle 1 before await')
await p
console.log('middle 1')
await next()
})
reducer.use(async (state, next) => {
state.name = 'test'
console.log('middle 2')
await next()
})
reducer.use(async (state, next) => {
state.name = 'm'
console.log('middle 3')
await next()
})
reducer.use((state, next) => {
state.name = 'm'
console.log('middle after 3')
next()
})
await reducer.start(state)
console.log('result')
console.log(state)
return state
}
async function runTest(params) {
const result = await test()
console.log('xxxx redulst')
console.log(result)
}
runTest()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment