手机版

深入分析koa中间件过程控制

时间:2021-08-22 来源:互联网 编辑:宝哥软件园 浏览:

前言

Koa被认为是第二代web后端开发框架。与上一代express相比,它最大的特点无疑是解决了回调金字塔的问题,使得异步编写更加简洁。在使用koa的过程中,我一直很好奇koa的内部实现机制。最近终于有时间深入学习koa的一些原理了,在这里我会写一系列的文章来记录我的学习经验和体会。

在我看来,koa的核心功能就是大家熟知的co,koa基于这个功能实现异步回调同步和中间件进程控制。当然,我不会在本文中分析co源代码。我打算在整个系列文章中一步步讲解如何实现koa中间件的进程控制原理和koa的异步回调同步编写原理。最后,在了解这些的基础上,我将实现一个类似于CO的简单功能。

本文首先只谈koa的中间件过程控制原理。

1.koa中间件执行过程

官网上有一个关于如何执行koa中间件的非常经典的例子。如果你有兴趣,可以看一下,不过在这里,我想稍微修改一下比较简单:

var KOA=require(' KOA ');var app=KOA();app . use(function *(next){ console . log(' begin middleware 1 ');接下来屈服;console.log('end中间件1 ');});app . use(function *(next){ console . log(' begin middleware 2 ');接下来屈服;console.log('end中间件2 ');});app . use(function *){ console . log('中间件3 ');});app . listen(3000);运行此示例,然后使用curl工具运行:

curl http://localhost:3000

如您所见,运行后,它将输出:

BeginMiddleware 1 BeginMiddleware 2中间件3 End中间件2 End中间件1这个例子形象地代表了koa的中间件执行机制,可以用下面的洋葱模型来描述:

通过这个执行过程,开发人员可以轻松地开发一些中间件,并将其集成到实际的业务流程中。那么,这个过程是如何实现和控制的呢?

2.韩国航空公司的发电机和作曲

简单来说,洋葱模型的执行过程是由es6中的生成器实现的。不熟悉发电机的同学可以看看它的特点。其中之一就是生成器函数可以像断点一样跳出某个地方,然后再回来继续执行。以下示例可以说明这一特性:

var gen=function *(console . log(' begin!');//yield语句,跳出这里,将控制权交给另一个func函数。产生另一种功能;//执行console.log('end!')下次回来时从这里开始);} var other func(){ console . log('这是另一个函数!');} var g=gen();var other=g . next();//“开始!”another是一个对象,其中value成员是返回的otherfunc函数other . value();//“这是另一个函数!”g . next();//“结束!”;从这个简单的例子中,我们可以看到洋葱模型最基本的雏形,即yield前后的语句先执行后执行,yield中间的代码在中心执行。

现在想象一下,如果收益率后面的函数本身就是一个生成器,会发生什么?事实上,它是上述示例的扩展:

var gen 1=function *(console . log(' begin!');产量G2;console.log('end!');} var gen 2=function *(console . log(' begin 2 ');产生另一种功能;console . log(' end 2 ');} var other func(){ console . log('这是另一个函数!');} var g=gen();var G2=gen 2();var other 1=g . next();//“开始!”;var other 2=other 1 . value . next();//“begin 2”;other 2 . value();//“这是另一个函数!”;other 1 . value . next();//“end 2”;g . next();//“结束!”;可以看到,上面的例子基本都用上了,加了一个嵌套。原理是一样的。

在koa中,每个中间件生成器都有一个下一个参数。在我们的例子中,g2可以看作是G函数的下一个参数。事实上,koa也是这么做的。使用app.use()挂载所有中间件后,koa有一个koa-compose模块,用于串联所有生成器中间件,基本上是将下一个生成器分配给前一个生成器的下一个参数。koa-compose的源代码非常简单和简短,下面是我自己实现的一个:

函数组合(middlewares返回函数(next){ var I=middleware . length;var next=function *(1){ }();while(I-){ next=middle ware[I]。打电话(这个,下一个);}下一步返回;}}用自己写的compose来转换上面的例子,更接近koa形式:

函数组合(middlewares返回函数(next){ var I=middleware . length;var next=function *(1){ }();while(I-){ next=middle ware[I]。打电话(这个,下一个);}下一步返回;} } var gen 1=function *(next){ console . log(' begin!');接下来屈服;console.log('end!');} var gen 2=function *(next){ console . log(' begin 2 ');接下来屈服;console . log(' end 2 ');} var gen 3=function *(next){ console . log('这是另一个函数!');}var bundle=compose([gen1,gen2,gen 3]);var g=bundle();var other 1=g . next();//“开始!”;var other 2=other 1 . value . next();//“begin 2”;other 2 . value . next();//“这是另一个函数!”;other 1 . value . next();//“end 2”;g . next();//“结束!”;最近怎么样?有没有koa中间件写作的感觉?但目前,我们仍在一步步手动执行我们的洋葱模型。我们可以写一个函数来自动执行我们的洋葱模型吗?

3.让洋葱模型自动运行:运行函数的编写

在上面的例子中,我们可以在最终代码中看到一个规则。基本上,外层生成器调用next方法将控制权交给内层,内层继续调用next将方法交给内层。整个过程可以用嵌套函数来编写。话不多说,直接打码:

函数run(gen){ var g;if(type of gen . next==' function '){ g=gen;} else { g=gen();} function next(){ var tmp=g . next();//如果tmp.done为真,则证明生成器执行完毕,返回。if(tmp . done){ return;} else if(type of g . next==' function '){ run(tmp . value);next();} } next();}函数compose(middleware){ return function(next){ var I=middleware . length;var next=function *(1){ }();while(I-){ next=middle ware[I]。打电话(这个,下一个);}下一步返回;} } var gen 1=function *(next){ console . log(' begin!');接下来屈服;console.log('end!');} var gen 2=function *(next){ console . log(' begin 2 ');接下来屈服;console . log(' end 2 ');} var gen 3=function *(next){ console . log('这是另一个函数!');}var bundle=compose([gen1,gen2,gen 3]);运行(捆绑);Run函数接受一个生成器,它的内部执行实际上是我们前面例子的简化,用递归的方法执行。运行这个例子,我们可以看到结果与我们前面的例子相同。

到目前为止,我们已经基本解释了koa中的中间件洋葱模型是如何自动执行的。事实上,在koa中使用的co的部分功能是实现这里编写的run函数的功能。

值得注意的是,本文只重点分析了中间件执行过程的实现,暂时没有考虑异步回调同步原理。在下一篇文章中,我将继续探讨koa中异步回调同步编写的机制。

本文的代码可以在github:https://github.com/mly-zju/async-js-demo,上找到,其中的文件process_control.js就是本文的案例源代码。

以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。

版权声明:深入分析koa中间件过程控制是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。