Skip to content

Instantly share code, notes, and snippets.

@yusukebe
Last active November 13, 2023 03:43
Show Gist options
  • Save yusukebe/608e6f15d06f91ba449fdf08c230ffa0 to your computer and use it in GitHub Desktop.
Save yusukebe/608e6f15d06f91ba449fdf08c230ffa0 to your computer and use it in GitHub Desktop.
type Callback = () => void | Promise<void>
type Middleware = (
c: C,
next: (callback?: Callback) => void
) => void | Promise<void> | string | Promise<string>
type C = {}
type Next = (callback?: Callback) => void | Promise<void>
const compose = (middleware: Middleware[]) => {
const callbacks: Callback[] = []
return function (c: C) {
let index = -1
return dispatch(0)
async function dispatch(i: number, callback?: () => void) {
if (i <= index) {
throw new Error('next() called multiple times')
}
if (callback) callbacks.unshift(callback)
index = i
const fn = middleware[i]
const res = fn(c, (cb) => {
dispatch(i + 1, cb)
})
if (res) {
let res2
if (res instanceof Promise) {
res2 = await res
} else {
res2 = res
}
if (res2) {
for (const callback of callbacks) {
if (callback) {
const res3 = callback()
if (res3 instanceof Promise) {
await res3
}
}
}
}
}
}
}
}
const a = (c: C, next: Next) => {
console.log('a-1')
next(() => {
console.log('a-2')
})
}
const b = async (c: C, next: Next) => {
console.log('b-1')
await new Promise((resolve) => setTimeout(resolve, 100))
console.log('b-1.2')
next(() => {
console.log('b-2')
})
}
const c = async (c: C, next: Next) => {
console.log('c-1')
next(async () => {
await new Promise((resolve) => setTimeout(resolve, 100))
console.log('c-2')
})
}
const h = async () => {
console.log('h')
await new Promise((resolve) => setTimeout(resolve, 100))
return 'foo'
}
const composed = compose([a, b, c, h])
await composed({})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment