Nodejs ミドルウェア Koa と Express を比較する

青灯夜游
リリース: 2021-02-24 09:52:14
転載
2296 人が閲覧しました

Nodejs ミドルウェア Koa と Express を比較する

関連する推奨事項: 「nodejs チュートリアル

ミドルウェアと言えば、多くの開発者は Koa.js を思い浮かべるでしょう。そして、そのミドルウェア設計は間違いなく優れています。フロントエンドミドルウェアの考え方の代表的なものの一つです。

最近コンテンツのこの部分を見直したところ、その素晴らしさについて読者の皆さんと話したいと思わずにはいられませんでした。


Koa は非常に使いやすく、Express と比べて「完璧なミドルウェア」設計のため、機能が非常にシンプルに見えます。作者はプロジェクトでこれを次のように使用しました:

const Koa=require('koa')
const app=new Koa()
const Router=require('koa-router')
const router=new Router()
const cors=require('koa2-cors')
const koaBody=require('koa-body')

const ENV='test-mpin2'

app.use(cors({
	origin:['http://localhost:9528'],   // 也可以写为:['*']
	credentials:true
}))
app.use(koaBody({
	multipart:true
}))
app.use(async(ctx,next)=>{
	console.log('访问全局中间件')
	ctx.state.env=ENV   // 全局缓存
	await next()
})

const playlist=require('./controller/playlist.js')
router.use('/playlist',playlist.routes())
const blog=require('./controller/blog.js')
router.use('/blog',blog.routes())

app.use(router.routes()).use(router.allowedMethods())

app.listen(3000,()=>{
	console.log('服务已开启')
})
ログイン後にコピー

これはルーティング ルーターを抽出して別のミドルウェアとして使用し、アプリはグローバル処理のみを担当します。別の例:

// 最外层中间件,可以用于兜底 Koa 全局错误
app.use(async (ctx, next) => {
  try {
    // 执行下一个中间件
    await next();
  } catch (error) {
    console.log(`[koa error]: ${error.message}`)
  }
});
// 第二层中间件,可以用于日志记录
app.use(async (ctx, next) => {
  const { req } = ctx;
  console.log(`req is ${JSON.stringify(req)}`);
  await next();
  console.log(`res is ${JSON.stringify(ctx.res)}`);
});
ログイン後にコピー

Koa を実装するだけです。

上記のコードに示すように、Koa インスタンスを確認し、use メソッドを通じてミドルウェアを登録および連結します。ソース コードの単純な実装は次のように表現できます:

use(fn) {
    this.middleware.push(fn);
    return this;
}
ログイン後にコピー

ミドルウェアを this.middleware に格納します。この配列では、ミドルウェアはどのように実行されるのでしょうか?以下のソース コードを参照してください。

// 通过 createServer 方法启动一个 Node.js 服务
listen(...args) {
    const server = http.createServer(this.callback());
    server.listen(...args);
}
ログイン後にコピー

Koa フレームワークは、http モジュールの createServer メソッドを通じて Node.js サービスを作成し、this.callback()# に渡します。 ## メソッド、コールバック ソース コード 簡単な実装は次のとおりです。

callback(){
	const fn=compose(this.middlewareList)
	
	return (req,res)=>{
		const ctx=createContext(req,res)
		return this.handleRequest(ctx,fn)
	}
}

handleRequest(ctx, fn) {
    const onerror = err => ctx.onerror(err);
    // 将 ctx 对象传递给中间件函数 fn
    return fn(ctx).catch(onerror);
}
ログイン後にコピー

上記のコードに示すように、Koa ミドルウェアの組み合わせと実行プロセスを次のステップに編成します。

    #メソッド (compose と呼びます) を通じて、さまざまなミドルウェアを結合し、ミドルウェア結合関数を返します
  • fn

  • リクエストが来ると、
  • handleRequest

    メソッドが最初に呼び出され、メソッドが完了します :

      createContext
    • メソッドを呼び出して、このリクエストの ctx オブジェクトをカプセル化します; 次に、
    • this.handleRequest(ctx, fn)# を呼び出します。 ##このリクエストを処理します。
    中核となるプロセスは、compose メソッドを使用してさまざまなミドルウェアを結合することです。これは別個のメソッドであり、Koa の残りのメソッドによって制約されるべきではありません。そのソース コードは次のように単純に実装されます:
  • // 组合中间件
    // 和express中的next函数意义一样
    function compose(middlewareList){
    	// return function意思是返回一个函数
    	return function(ctx,next){
    		// 各种中间件调用的逻辑
    		function dispatch(i){
    			const fn=middlewareList[i] || next
    			if(fn){
    				try{
    					// koa中都是async,其返回的是一个promise(对象)
    					return Promise.resolve(fn(ctx,function next(){
    						return dispatch(i+1)
    					}))
    				}catch(err){
    					return Promise.reject(err)
    				}
    			}else{
    				return Promise.resolve()
    			}
    		}
    		return dispatch(0)
    	}
    }
    ログイン後にコピー
その機能は次のように表現できます (非ソース コード):

async function middleware1() {
  //...
  await (async function middleware2() {
    //...
    await (async function middleware3() {
      //...
    });
    //...
  });
  //...
}
ログイン後にコピー

この時点で、実際にその機能を「最初に垣間見る」ことができます。

Koa のミドルウェア メカニズムは、コミュニティによってオニオン モデルとして鮮やかに要約されています;

  • いわゆるオニオン モデルとは、次のことを意味します。各 Koa ミドルウェアはオニオン リングの層であり、リクエストの入力とレスポンスの戻りの両方を処理できます。言い換えれば、外側のミドルウェアは内側の層の要求フェーズと応答フェーズに影響を与えることができ、内側のミドルウェアは外側層の応答フェーズにのみ影響を与えることができます。

dispatch(n) は、n 番目のミドルウェアの実行に対応します。使用中に、n 番目のミドルウェアを「挿入」して、await next() を通じて次のミドルウェアを実行できます。同時に、最後のミドルウェアの実行が完了した後も、実行を再開することができます。つまり、オニオン モデルを通じて、await next() は、世界中に実行可能なミドルウェアがなくなり、スタックの実行が完了するまで後続のミドルウェアの呼び出しを制御し、最後に次に実行する最初のミドルウェアへの「元のパスに戻ります」。 。
この方法には、特に、非常に使いやすくする必要があるロギングやエラー処理などのグローバル関数の場合に利点があります。
  • Koa1 のミドルウェア実装では、Generator 関数 co ライブラリ (Promise に基づいた Generator 関数プロセス管理ツール) を使用してコルーチンの実行を実装します。本質的に、Koa v1 ミドルウェアと Koa v2 ミドルウェアの考え方は似ていますが、Koa v2 では Generator 関数の co ライブラリを置き換えるために Async/Await が使用される点が異なり、全体的な実装はより賢明で、コードはより洗練されています。 —— 「Wolf Book」より
ソース コードの上記の部分を記述した後、es6 を使用してそれを組み合わせることができます:

// myKoa.js文件

const http=require('http')

function compose(){}   //见上

class LikeKoa2{
	constructor() {
	    this.middlewareList=[]
	}
	use(){}   //见上
	
	// 把所有的req,res属性、事件都交给ctx(这里只是简写)
	createContext(req,res){
		const ctx={
			req,
			res
		}
		// 比如
		ctx.query=req,query
		return ctx
	}
	handleRequest(){}   //见上
	callback(){}   //见上
	listen(){}   //见上
}

// koa和express的不同之一:
// express在调用时直接调用函数:const app=express();所以暴露出去new过的对象——具体见下面链接中代码
// 但是koa调用时以类的方式:const app=new Koa();所以直接暴露出去
module.exports=LikeKoa2
ログイン後にコピー

使用方法は他の方法と同じではありません. 連動していますが、どのように実行されますか? createServer実行後、チャネルを確立してlisten機能を実装するのと同じでしょうか?
申し訳ありませんが、これについては Node のソース コードで詳しく調べる必要があります...


Koa と比較し、Express の原理について話します


Node.js フレームワークといえば、Express を忘れてはなりません。Koa とは異なり、ルーティング、静的サーバー、テンプレート エンジンなどの機能を継承しています。Koa に比べてはるかに「肥大化」していますが、見た目はフレームワークに似ています。コアよりも。 Express のソース コードを調べて、作成者はその動作メカニズムを簡単に要約しました。

app.use メソッドを通じてミドルウェアを登録します。

  • ミドルウェアは、現在のルートとハンドル メソッドに一致する通常の情報を含む Layer オブジェクトとして理解できます。

  • すべてのミドルウェア (レイヤー オブジェクト) は、スタック配列を使用して保存されます。

  • リクエストが来ると、reqからリクエストのパスを取得し、そのパスに従ってスタックから一致するLayerを探します。具体的なマッチング処理は#によって行われます。 ##router.handle

    関数が完了します。
  • router.handle

    関数は、
  • next()
  • メソッドを使用して比較のために各レイヤーを走査します。
    • next()方法通过闭包维持了对于 Stack Index 游标的引用,当调用next()方法时,就会从下一个中间件开始查找;
    • 如果比对结果为 true,则调用layer.handle_request方法,layer.handle_request方法中会调用next()方法 ,实现中间件的执行。

通过上述内容,我们可以看到,Express 其实是通过 next() 方法维护了遍历中间件列表的 Index 游标,中间件每次调用next()方法时,会通过增加 Index 游标的方式找到下一个中间件并执行。它的功能就像这样:

((req, res) => {
  console.log('第一个中间件');
  ((req, res) => {
    console.log('第二个中间件');
    (async(req, res) => {
      console.log('第三个中间件');
      await sleep(2000)
      res.status(200).send('hello')
    })(req, res)
    console.log('第二个中间件调用结束');
  })(req, res)
  console.log('第一个中间件调用结束')
})(req, res)
ログイン後にコピー

如上代码,Express 中间件设计并不是一个洋葱模型,它是基于回调实现的线形模型,不利于组合,不利于互操,在设计上并不像 Koa 一样简单。而且业务代码有一定程度的侵扰,甚至会造成不同中间件间的耦合。

express的简单实现笔者已上传至腾讯微云,需要者可自行查看&下载:express的简单实现

更多编程相关知识,请访问:编程视频!!

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

関連ラベル:
ソース:csdn.net
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!