JavaScript의 기본 미들웨어 패턴
17403 단어 middlewarekoatypescriptjavascript
Express에는 다음과 같은 서명이 있는 미들웨어 기능이 있습니다.
const middleare = (req, res, next) => {
// do stuffs
next()
}
Koa에는 다음이 있습니다.
const middleware = (ctx, next) => {
// do stuffs
next()
}
기본적으로 미들웨어 함수의 인수로 일부 객체(
req
, res
Express 또는 ctx
Koa) 및 next()
함수가 있습니다. next()
가 호출되면 다음 미들웨어 기능이 호출됩니다. 현재 미들웨어 함수에서 인수 객체를 수정하면 다음 미들웨어는 수정된 객체를 받습니다. 예를 들어:// Middleware usage in Koa
app.use((ctx, next) => {
ctx.name = 'Doe'
next()
})
app.use((ctx, next) => {
console.log(ctx.name) // will log `Doe`
})
app.use((ctx, next) => {
// this will not get invoked
})
그리고
next()
함수를 호출하지 않으면 거기에서 실행이 중지되고 다음 미들웨어 함수가 호출되지 않습니다.구현
그렇다면 어떻게 그런 패턴을 구현합니까? 30줄의 JavaScript:
function Pipeline(...middlewares) {
const stack = middlewares
const push = (...middlewares) => {
stack.push(...middlewares)
}
const execute = async (context) => {
let prevIndex = -1
const runner = async (index) => {
if (index === prevIndex) {
throw new Error('next() called multiple times')
}
prevIndex = index
const middleware = stack[index]
if (middleware) {
await middleware(context, () => {
return runner(index + 1)
})
}
}
await runner(0)
}
return { push, execute }
}
이 미들웨어 패턴의 구현은 Koa와 거의 동일합니다. Koa가 어떻게 하는지 알고 싶다면
koa-compose
패키지의 소스 코드를 확인하십시오.용법
사용 예를 살펴보겠습니다.
// create a middleware pipeline
const pipeline = Pipeline(
// with an initial middleware
(ctx, next) => {
console.log(ctx)
next()
}
)
// add some more middlewares
pipeline.push(
(ctx, next) => {
ctx.value = ctx.value + 21
next()
},
(ctx, next) => {
ctx.value = ctx.value * 2
next()
}
)
// add the terminating middleware
pipeline.push((ctx, next) => {
console.log(ctx)
// not calling `next()`
})
// add another one for fun ¯\_(ツ)_/¯
pipeline.push((ctx, next) => {
console.log('this will not be logged')
})
// execute the pipeline with initial value of `ctx`
pipeline.execute({ value: 0 })
해당 코드를 실행하면 어떤 결과가 나올지 짐작할 수 있습니까? 예, 당신이 올바르게 추측했습니다.
{ value: 0 }
{ value: 42 }
그건 그렇고, 이것은 비동기 미들웨어 기능에서도 절대적으로 작동합니다.
타입스크립트
이제 TypeScript에 애정을 쏟는 것은 어떻습니까?
type Next = () => Promise<void> | void
type Middleware<T> = (context: T, next: Next) => Promise<void> | void
type Pipeline<T> = {
push: (...middlewares: Middleware<T>[]) => void
execute: (context: T) => Promise<void>
}
function Pipeline<T>(...middlewares: Middleware<T>[]): Pipeline<T> {
const stack: Middleware<T>[] = middlewares
const push: Pipeline<T>['push'] = (...middlewares) => {
stack.push(...middlewares)
}
const execute: Pipeline<T>['execute'] = async (context) => {
let prevIndex = -1
const runner = async (index: number): Promise<void> => {
if (index === prevIndex) {
throw new Error('next() called multiple times')
}
prevIndex = index
const middleware = stack[index]
if (middleware) {
await middleware(context, () => {
return runner(index + 1)
})
}
}
await runner(0)
}
return { push, execute }
}
모든 것이 입력되면 다음과 같이 특정 미들웨어 파이프라인에 대한 컨텍스트 개체의 유형을 선언할 수 있습니다.
type Context = {
value: number
}
const pipeline = Pipeline<Context>()
좋아, 지금은 그게 다야.
2020년 10월 4일 muniftanjim.dev에 원래 게시되었습니다.
Reference
이 문제에 관하여(JavaScript의 기본 미들웨어 패턴), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/muniftanjim/basic-middleware-pattern-in-javascript-33on텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)