perf(core): optimized middlewares composition
MODIFY
package.json
package.json
"scripts": {
"postinstall": "npm run build",
"build": "lerna link && lerna bootstrap --hoist",
- "benchmark": "npm run build && make -C benchmarks",
+ "benchmark": "make -C benchmarks",
"lint": "tslint --config tslint.json --project tsconfig.spec.json",
"test": "jest --expand",
"test:coverage": "jest --expand --coverage",

MODIFY
packages/core/src/effects/effects.combiner.ts
packages/core/src/effects/effects.combiner.ts
-import { concat, of } from 'rxjs';
-import { concatMap, mergeMap, switchMap } from 'rxjs/operators';
+import { concat, from, of } from 'rxjs';
+import { concatMap, last, mergeMap } from 'rxjs/operators';
import { HttpRequest } from '../http.interface';
import { matchPath } from '../operators';
import { isGroup, isRouteCombinerConfig } from './effects.helpers';
-import { EffectCombiner, MiddlewareCombiner, RouteCombiner } from './effects.interface';
+import { Effect, EffectCombiner, MiddlewareCombiner, RouteCombiner } from './effects.interface';
-export const combineEffects: EffectCombiner = effects => res => req => {
+export const combineEffects: EffectCombiner = effects => {
+ return res => req => {
const req$ = of(req);
const mappedEffects = effects.map(effect => isGroup(effect)
? req$.pipe(
@@ -18,13 +19,16 @@ export const combineEffects: EffectCombiner = effects => res => req => {
return concat(...mappedEffects);
};
+};
-export const combineMiddlewareEffects: MiddlewareCombiner = effects => res => req => {
- const req$ = of(req);
- const mappedEffects = effects.map(effect =>
- switchMap((mappedReqest: HttpRequest) => effect(of(mappedReqest), res, undefined))
+export const combineMiddlewareEffects: MiddlewareCombiner = effects => {
+ const middlewares = middlewaresGuard(effects);
+ return res => req => {
+ return from(middlewares).pipe(
+ concatMap(effect => effect(of(req), res, undefined)),
+ last(),
);
- return req$.pipe(...mappedEffects);
+ };
};
export const combineRoutes: RouteCombiner = (path, configOrEffects) => ({
@@ -32,3 +36,10 @@ export const combineRoutes: RouteCombiner = (path, configOrEffects) => ({
effects: isRouteCombinerConfig(configOrEffects) ? configOrEffects.effects : configOrEffects,
middlewares: isRouteCombinerConfig(configOrEffects) ? (configOrEffects.middlewares || []) : [],
});
+
+const middlewaresGuard = (middlewares: Effect<HttpRequest>[]) => {
+ const emptyMiddleware: Effect<HttpRequest> = req => req;
+ return middlewares.length
+ ? middlewares
+ : [emptyMiddleware];
+};

MODIFY
packages/core/src/http.listener.ts
packages/core/src/http.listener.ts
@@ -19,14 +19,20 @@ export const httpListener = ({
errorMiddleware,
}: HttpListenerConfig) => {
const request$ = new Subject<Http>();
+
+ const combinedMiddlewares = combineMiddlewareEffects(middlewares);
+ const combinedEffects = combineEffects(effects);
+ const providedErrorMiddleware = getErrorMiddleware(errorMiddleware);
+ const defaultResponse = { status: HttpStatus.NOT_FOUND } as EffectResponse;
+
const effect$ = request$.pipe(
mergeMap(({ req, res }) =>
- combineMiddlewareEffects(middlewares)(res)(req).pipe(
- switchMap(combineEffects(effects)(res)),
- defaultIfEmpty({ status: HttpStatus.NOT_FOUND } as EffectResponse),
+ combinedMiddlewares(res)(req).pipe(
+ switchMap(combinedEffects(res)),
+ defaultIfEmpty(defaultResponse),
tap(handleResponse(res)(req)),
catchError(error =>
- getErrorMiddleware(errorMiddleware)(of(req), res, error).pipe(
+ providedErrorMiddleware(of(req), res, error).pipe(
tap(handleResponse(res)(req)),
),
),

perf(core): optimized middlewares composition