← Wszystkie zadaniaNode.js · Middle
Łańcuch middleware jak w Koa
Napisz compose(middlewares): zwraca funkcję (ctx) => Promise, która uruchamia middleware po kolei. Każde dostaje ctx i next; await next() przekazuje sterowanie następnemu i czeka, aż reszta łańcucha się zakończy, a kod po nim wykonuje się w drodze powrotnej („cebula”).
Jeśli middleware nie wywoła next(), reszta się nie wykona. Błąd w dowolnym middleware (synchroniczny lub asynchroniczny) odrzuca obietnicę i można go złapać try/catch wokół await next() wyżej w łańcuchu. Ponowne wywołanie next() w jednym middleware to błąd next() called multiple times.
Ctrl+Enter uruchamia testy. Tab robi wcięcie; aby wyjść z edytora klawiaturą, naciśnij Esc, a potem Tab. Kod zapisuje się w tej przeglądarce.
Testy (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([])({});