In diesem Artikel wird hauptsächlich der detaillierte Vergleich zwischen Express- und Koa-Middleware-Modi vorgestellt. Der Herausgeber findet ihn recht gut, daher werde ich ihn jetzt mit Ihnen teilen und als Referenz verwenden. Folgen wir dem Editor und werfen wir einen Blick darauf.
Ursache
Ich habe kürzlich gelernt, wie man Koa verwendet, ein ziemlich einfaches Web-Framework, ein vollständiges Webanwendungen sind Die meisten erforderlichen Dinge werden in Form von Middleware eingeführt, z. B. Koa-Router, Koa-View usw. In der Dokumentation von Koa wird Folgendes erwähnt: Das Middleware-Modell von Koa ist zwiebelförmig, während Express linear ist. Viele Artikel im Internet liefern keine detaillierte Analyse. Oder einfacher ausgedrückt, es sind die Eigenschaften von async/await. Reden wir nicht darüber, ob diese Aussage richtig oder falsch ist. Für mich ist diese Aussage noch zu vage. Deshalb habe ich beschlossen, die Ähnlichkeiten und Unterschiede in den Prinzipien und der Verwendung der beiden Middleware-Implementierungen anhand des Quellcodes zu analysieren.
Der Einfachheit halber wird hier express durch connect ersetzt (das Implementierungsprinzip ist das gleiche)
Verwendung
Beide sind im dokumentiert offizielle Website (Github) Vorbehaltlich
connect
Die Nutzung der offiziellen Website erfolgt wie folgt:
var connect = require('connect'); var http = require('http'); var app = connect(); // gzip/deflate outgoing responses var compression = require('compression'); app.use(compression()); // store session state in browser cookie var cookieSession = require('cookie-session'); app.use(cookieSession({ keys: ['secret1', 'secret2'] })); // parse urlencoded request bodies into req.body var bodyParser = require('body-parser'); app.use(bodyParser.urlencoded({extended: false})); // respond to all requests app.use(function(req, res){ res.end('Hello from Connect!\n'); }); //create node.js http server and listen on port http.createServer(app).listen(3000);
Dem Dokument zufolge bietet connect eine einfache Routing-Funktion:
app.use('/foo', function fooMiddleware(req, res, next) { // req.url starts with "/foo" next(); }); app.use('/bar', function barMiddleware(req, res, next) { // req.url starts with "/bar" next(); });
Die Middleware von connect ist linear. Weiter geht es mit Suchen Sie nach der nächsten Middleware. Es ist auch leicht zu verstehen, dass Middleware eine Reihe von Arrays ist. Tatsächlich wird connect auch auf diese Weise implementiert.
app.use dient dazu, neue Middleware in das Middleware-Array einzufügen. Die Ausführung von Middleware ist für die Verarbeitung auf die private Methode app.handle angewiesen, und das Gleiche gilt für Express.
koa
Im Vergleich zu connect ist das Middleware-Modell von koa nicht so intuitiv. Nehmen wir die grafische Darstellung aus dem Internet:
Das heißt, Koa wird nach der Verarbeitung der Middleware zurückkommen, was uns mehr Spielraum für den Betrieb gibt. Schauen wir uns das offizielle Website-Beispiel von Koa an:
const Koa = require('koa'); const app = new Koa(); // x-response-time app.use(async (ctx, next) => { const start = Date.now(); await next(); const ms = Date.now() - start; ctx.set('X-Response-Time', `${ms}ms`); }); // logger app.use(async (ctx, next) => { const start = Date.now(); await next(); const ms = Date.now() - start; console.log(`${ctx.method} ${ctx.url} - ${ms}`); }); // response app.use(async ctx => { ctx.body = 'Hello World'; }); app.listen(3000);
Wenn Koa-Verarbeitungs-Middleware auf next() trifft, wird die aktuelle Middleware angehalten und die nächste Middleware verarbeitet, und schließlich wird die Verarbeitung der verbleibenden Aufgaben fortgesetzt, obwohl das sehr kompliziert zu sagen ist , aber intuitiv haben wir ein vage vertrautes Gefühl: Ist es nicht nur eine Rückruffunktion? Lassen Sie uns hier nicht über die spezifische Implementierungsmethode sprechen, aber es handelt sich tatsächlich um eine Rückruffunktion. Es hat nichts mit den Funktionen von async/await zu tun.
Kurzanalyse des Quellcodes
Der Hauptunterschied zwischen dem Connect- und dem Koa-Middleware-Modus liegt in der Implementierung von next zwischen den beiden .
connect
Der Quellcode von connect ist recht klein und umfasst nur etwa 200 Zeilen mit Kommentaren. Es scheint sehr klar, dass die Connect-Middleware-Verarbeitung im privaten Methodenproto liegt .handle. , ähnlich wird hier auch next implementiert
// 中间件索引 var index = 0 function next(err) { // 递增 var layer = stack[index++]; // 交由其他部分处理 if (!layer) { defer(done, err); return; } // route data var path = parseUrl(req).pathname || '/'; var route = layer.route; // 递归 // skip this layer if the route doesn't match if (path.toLowerCase().substr(0, route.length) !== route.toLowerCase()) { return next(err); } // call the layer handle call(layer.handle, route, err, req, res, next); }
Nachdem wir den verschleierten Code gelöscht haben, können wir sehen, dass die nächste Implementierung ebenfalls sehr einfach ist. Eine rekursive Aufrufsequenz auf der Suche nach Middleware. Rufen Sie als Nächstes weiter an. Der Code ist recht einfach, aber die Idee ist es wert, erlernt zu werden.
Wo erledigt ist die Drittanbieter-Verarbeitungsmethode. Andere Teile, die sich mit Sub-Apps und Routing befassen, wurden gelöscht. Nicht der Punkt
koa
koa trennt die Implementierung von next in ein separates Paket. Der Code ist einfacher, implementiert aber eine scheinbar komplexere Funktion
function compose (middleware) { return function (context, next) { // last called middleware # let index = -1 return dispatch(0) function dispatch (i) { index = i try { return Promise.resolve(fn(context, function next () { return dispatch(i + 1) })) } catch (err) { return Promise.reject(err) } } } }
Wenn man sich den oben verarbeiteten Code ansieht, sind einige Schüler möglicherweise immer noch verwirrt.
Dann fahren wir mit der Verarbeitung fort:
function compose (middleware) { return function (context, next) { // last called middleware # let index = -1 return dispatch(0) function dispatch (i) { index = i let fn = middleware[i] if (i === middleware.length) { fn = next } if (!fn) return return fn(context, function next () { return dispatch(i + 1) }) } } }
Auf diese Weise ist das Programm einfacher und hat nichts mit async/await zu tun Ergebnis ist gut
var ms = [ function foo (ctx, next) { console.log('foo1') next() console.log('foo2') }, function bar (ctx, next) { console.log('bar1') next() console.log('bar2') }, function qux (ctx, next) { console.log('qux1') next() console.log('qux2') } ] compose(ms)()
Wenn wir das obige Programm ausführen, können wir die Ausgabe in der Reihenfolge finden:
foo1
bar1
qux1
qux2
bar2
foo2
ist auch das sogenannte Zwiebelmodell von Koa. An dieser Stelle können wir den Schluss ziehen, dass das Middleware-Modell von Koa keine tatsächliche Verbindung mit Async oder Generator hat , aber Koa betont die asynchrone Priorität. Die sogenannte Middleware-Pause ist nur auf die Callback-Funktion zurückzuführen (meiner Meinung nach gibt es keinen Unterschied zwischen Promise.then und Callback, und sogar Async/Await ist auch eine Form des Callbacks).
Das obige ist der detaillierte Inhalt vonVergleichen Sie die Unterschiede und Zusammenhänge zwischen Express- und Koa-Middleware-Mustern. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!