Maison > interface Web > js tutoriel > le corps du texte

Comparez les middlewares nodejs Koa et Express

青灯夜游
Libérer: 2021-02-24 09:52:14
avant
2297 Les gens l'ont consulté

Comparez les middlewares nodejs Koa et Express

Recommandations associées : "Tutoriel nodejs"

Quand il s'agit de middleware, de nombreux développeurs penseront à Koa.js et à sa conception middleware est sans aucun doute l'un des représentants typiques de la pensée middleware front-end.

En réexaminant cette partie récemment, je n'ai pas pu m'empêcher de vouloir discuter avec vous, lecteurs, de sa merveille !


Koa est très pratique à utiliser - comparé à Express, sa conception de "middleware parfait" rend les fonctions très simples ! L'auteur l'a utilisé dans le projet :

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('服务已开启')
})
Copier après la connexion

Il extrait le routeur de routage et l'utilise comme middleware distinct, et l'application n'est responsable que du traitement global. Autre exemple :

// 最外层中间件,可以用于兜底 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)}`);
});
Copier après la connexion

Facile à mettre en œuvre un Koa !

Comme le montre le code ci-dessus, nous examinons l'instance Koa, enregistrons et concaténons le middleware via la méthode use, et la simple implémentation du code source peut être exprimée comme suit :

use(fn) {
    this.middleware.push(fn);
    return this;
}
Copier après la connexion

Nous stockons le middleware dans this.middlewareDans le tableau, comment le middleware est-il exécuté ? Reportez-vous au code source ci-dessous :

// 通过 createServer 方法启动一个 Node.js 服务
listen(...args) {
    const server = http.createServer(this.callback());
    server.listen(...args);
}
Copier après la connexion

Le framework Koa crée un service Node.js via la méthode createServer du module http, et transmet la méthode this.callback() L'implémentation simple de la source de rappel. le code est le suivant :

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);
}
Copier après la connexion

comme ci-dessus Code, nous organisons un processus de composition et d'exécution de middleware de Koa en les étapes suivantes :

  • Combinez divers middleware via une méthode ( nous l'appelons composer) et renvoie une fonction de composition middleware fn

  • Lorsqu'une requête arrive, la méthode handleRequest sera appelée en premier et la méthode est terminée :

    • appelle la méthode createContext pour cette requête Encapsulez un objet ctx
    • puis appelle this.handleRequest(ctx, fn) pour gérer la requête.

Parmi eux, le processus principal consiste à utiliser la méthode compose pour combiner divers middlewares - il s'agit d'une méthode distincte, et elle ne devrait pas être contrainte par le reste des méthodes de Koa. . Son code source est simplement implémenté comme :

// 组合中间件
// 和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)
	}
}
Copier après la connexion

Sa fonction peut être exprimée ainsi (code non source) :

async function middleware1() {
  //...
  await (async function middleware2() {
    //...
    await (async function middleware3() {
      //...
    });
    //...
  });
  //...
}
Copier après la connexion

À ce stade, nous pouvons en fait avoir un "premier aperçu" de son En principe, il y a deux points :

  • Le mécanisme middleware de Koa est clairement résumé par la communauté comme un modèle d'oignon

Le soi-disant modèle d'oignon signifie que chaque middleware Koa est une couche de rondelles d'oignon. Il peut gérer à la fois la saisie des requêtes et le retour des réponses. En d’autres termes : le middleware externe peut affecter les phases de requête et de réponse de la couche interne, et le middleware interne ne peut affecter que la phase de réponse de la couche externe.

  • dispatch(n) correspond à l'exécution du nième middleware En utilisation, le nième middleware peut être "inséré" pour exécuter le prochain middleware via wait next() en même temps. Une fois l'exécution du dernier middleware terminée, il est toujours possible de reprendre l'exécution. Autrement dit : via le modèle oignon, wait next() contrôle l'appel du middleware suivant jusqu'à ce qu'il n'y ait plus de middleware exécutable globalement et que la pile soit exécutée, et enfin "revienne au chemin d'origine" vers le premier middleware qui s'exécute ensuite. Cette approche présente des avantages, notamment pour les fonctions globales telles que la journalisation et la gestion des erreurs qui doivent être très conviviales.

L'implémentation du middleware de Koa1 utilise la bibliothèque Generator function + co (un outil de gestion de processus de fonction Generator basé sur Promise) pour implémenter l'exécution de la coroutine. Essentiellement, les idées du middleware Koa v1 et du middleware Koa v2 sont similaires, sauf que Koa v2 utilise Async/Await pour remplacer la fonction Generator + la bibliothèque co. L'implémentation globale est plus intelligente et le code est plus élégant. —— de "Wolf Book"

Après avoir décrit la partie ci-dessus du code source, nous pouvons la combiner en utilisant 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
Copier après la connexion

La méthode d'utilisation n'est pas la même que les autres méthodes . Interconnecté, comment est-il exécuté ? Après avoir exécuté createServer, cela équivaut-il à établir un canal et à monter une fonction d'écoute ?
J'ai bien peur que nous devions en savoir plus à ce sujet dans le code source de Node...


En comparaison avec Koa, parlons des principes d'Express

En parlant de framework Node.js, il ne faut pas oublier Express - contrairement à Koa, il hérite de fonctions telles que le routage, le serveur statique et le moteur de template. Bien qu'il soit "gonflé" par rapport à Koa, il ressemble plus à un framework Node.js. cadre que Koa. En étudiant le code source d'Express, l'auteur a simplement résumé son mécanisme de fonctionnement :

  • Enregistrez le middleware via la méthode app.use.

  • Un middleware peut être compris comme un objet Layer, qui contient les informations régulières correspondant à l'itinéraire actuel et à la méthode handle.

  • Tous les middleware (objets Layer) sont stockés à l'aide du tableau de pile.

  • Lorsqu'une requête arrive, le chemin de la requête sera obtenu à partir de req et la couche correspondante sera trouvée dans la pile en fonction du chemin. Le processus de correspondance spécifique est implémenté par le <. 🎜> fonction. La fonction router.handle

  • parcourt chaque couche via la méthode router.handle à des fins de comparaison : next()

    • next()方法通过闭包维持了对于 Stack Index 游标的引用,当调用next()方法时,就会从下一个中间件开始查找;
    • 如果比对结果为 true,则调用layer.handle_request方法,layer.handle_request方法中会调用next()方法 ,实现中间件的执行。

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

((req, res) => {
  console.log(&#39;第一个中间件&#39;);
  ((req, res) => {
    console.log(&#39;第二个中间件&#39;);
    (async(req, res) => {
      console.log(&#39;第三个中间件&#39;);
      await sleep(2000)
      res.status(200).send(&#39;hello&#39;)
    })(req, res)
    console.log(&#39;第二个中间件调用结束&#39;);
  })(req, res)
  console.log(&#39;第一个中间件调用结束&#39;)
})(req, res)
Copier après la connexion

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

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

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:csdn.net
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!