ホームページ  >  記事  >  ウェブフロントエンド  >  Express と koa ミドルウェア パターンの違いと関連性を比較する

Express と koa ミドルウェア パターンの違いと関連性を比較する

巴扎黑
巴扎黑オリジナル
2017-08-11 10:08:572591ブラウズ

この記事では、Express と koa ミドルウェア モードの詳細な比較を主に紹介しています。編集者が非常に優れていると考えたので、参考として共有します。エディターをフォローして見てみましょう

原因

私は最近koaの使い方を勉強しています。koaはかなり基本的なWebフレームワークなので、完全なWebアプリケーションに必要なもののほとんどが次の形式で紹介されています。 koa-router、koa-view などのミドルウェアのこれは koa のドキュメントに記載されています。koa のミドルウェア モデルは、express のモデルとは異なります。なぜそうなるのかについては、インターネット上の多くの記事で詳細な分析が行われていません。簡単に言えば、async/await の特性です。この発言が正しいか間違っているかについては、私にとってはまだ曖昧すぎます。そこで、ソース コードを通じて 2 つのミドルウェア実装の原理と使用法の類似点と相違点を分析することにしました。

簡単のため、ここでのexpressはconnectに置き換えられます(実装原理は同じです)

使い方

どちらも公式サイト(github)のドキュメントに準じます

connect

以下は公式 Web サイトの使用法:


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);

ドキュメントによると、connect は単純なルーティング機能を提供していることがわかります:


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();
});

connect のミドルウェアは次のミドルウェアを検索し続けます。このモードは、ミドルウェアが一連の配列であり、ルート マッチングによって対応するルートを見つける処理方法がミドルウェアであることを理解しやすいです。実際、connect もこの方法で実装されています。

app.use は、新しいミドルウェアをミドルウェア配列に挿入することです。ミドルウェアの実行はプライベート メソッド app.handle に依存して処理され、同じ原則が Express にも適用されます。

koa

koa のミドルウェア モデルは、connect と比べるとそれほど直感的ではありません。インターネットから図を借りて表現してみましょう。

つまり、koa はミドルウェアを処理した後に戻ってきます。より大きな操作領域を提供するために、koa の公式 Web サイトの例を見てみましょう:


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);

明らかに、koa 処理ミドルウェアが await next() に遭遇すると、現在のミドルウェアを一時停止し、次のミドルウェアを処理します。最後に、戻って残りのタスクの処理を続けます。複雑な言い方ですが、直感的には、これはコールバック関数ではないかという感覚が得られます。ここでは具体的な実装方法については触れませんが、これは確かにコールバック関数です。 async/await の機能とは何の関係もありません。

ソースコードの簡単な分析

Connect と koa ミドルウェア モードの主な違いは、next の実装にあります。この 2 つの間の next の実装を簡単に見てみましょう。

connect

connect のソースコードは非常に小さく、コメントも含めて約 200 行だけですが、connect ミドルウェアの処理はプライベート メソッド proto.handle にあり、next もここに実装されています


// 中间件索引
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);
 }

難読化されたコードを削除した後、次の実装も非常に単純であることがわかります。ミドルウェアを探す再帰呼び出しシーケンス。次に電話をかけ続けます。コードは非常に単純ですが、このアイデアは学ぶ価値があります。

ここで行われるのは、サードパーティの処理方法です。サブアプリとルーティングを扱う他の部分は削除されました。重要ではありません

koa

koa は next の実装を別のパッケージに分離しています。コードはより単純ですが、一見より複雑な関数を実装しています


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)
  }
 }
 }
}

上記で処理されたコードを見ると、まだ学生もいるかもしれません。それに気づかない。

それでは、処理を続けてみましょう:


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)
  })
 }
 }
}

このように、プログラムはより単純になり、async/awaitとは何の関係もありません。結果を見てみましょう


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)()

上記のプログラムを実行できます。

foo1
bar1
qux1
qux2
bar2
foo2

というシーケンスの出力も、koa のいわゆるオニオン モデルであることがわかります。この時点で、koa のミドルウェア モデルには何もないという結論を導くことができます。 async またはジェネレーターとの関係 実際の関係は、koa が非同期の優先順位を強調していることです。いわゆるミドルウェアの一時停止は、コールバック関数によってのみ発生します (私の意見では、promise.then とコールバックの間に違いはなく、async/await もコールバックの一種です)。

以上がExpress と koa ミドルウェア パターンの違いと関連性を比較するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。