← Усі задачіNode.js · Middle
Ланцюжок middleware як у Koa
Напишіть compose(middlewares): він повертає функцію (ctx) => Promise, що запускає middleware по черзі. Кожне отримує ctx і next; await next() передає керування наступному й чекає, доки решта ланцюжка завершиться, а код після нього виконується на зворотному шляху («цибулина»).
Якщо middleware не викликав next(), решта не виконується. Помилка в будь-якому middleware (синхронна чи асинхронна) відхиляє проміс і її можна перехопити try/catch навколо await next() вище за ланцюжком. Повторний виклик next() в одному middleware - помилка next() called multiple times.
Ctrl+Enter - запустити тести. Tab - відступ; щоб вийти з редактора клавіатурою, натисніть Esc, а потім Tab. Код зберігається в цьому браузері.
Тести (6)
const log = []; const app = compose([ async (ctx, next) => { log.push('a1'); await next(); log.push('a2'); }, async (ctx, next) => { log.push('b1'); await next(); log.push('b2'); }, async () => { log.push('c'); }, ]); await app({}); expect(log).toEqual(['a1', 'b1', 'c', 'b2', 'a2']);
const app = compose([ async (ctx, next) => { ctx.user = 'ann'; await next(); }, async (ctx) => { ctx.body = 'hello ' + ctx.user; }, ]); const ctx = {}; await app(ctx); expect(ctx.body).toBe('hello ann');
const third = fn(); const app = compose([ async (ctx, next) => { ctx.status = 401; }, async () => third(), ]); const ctx = {}; await app(ctx); expect(ctx.status).toBe(401); expect(third).toHaveBeenCalledTimes(0);
const app = compose([ async (ctx, next) => { try { await next(); } catch (e) { ctx.status = 500; ctx.error = e.message; } }, async () => { throw new Error('db down'); }, ]); const ctx = {}; await app(ctx); expect(ctx).toEqual({ status: 500, error: 'db down' });
const app = compose([async (ctx, next) => { await next(); await next(); }]); await expect(app({})).rejects.toThrow('next() called multiple times');
const app = compose([(ctx, next) => { throw new Error('sync boom'); }]); await expect(app({})).rejects.toThrow('sync boom'); await compose([])({});