koa中间件的实现原理

news2025/2/25 21:01:08

koa中间件的实现原理如何?先来看一个例子。

koa的执行顺序是这样的:

const middleware = asyncfunction (ctx, next) {
  console.log(1)
  await next()
  console.log(6)
}

const middleware2 = asyncfunction (ctx, next) {
  console.log(2)
  await next()
  console.log(5)
}

const middleware3 = asyncfunction (ctx, next) {
  console.log(3)
  await next()
  console.log(4)
} 

会依次打印1,2,3,4,5,6

问题是koa中间件实现原理,也就是洋葱模型的实现原理是什么?

一、问题分析

async await是promise的语法糖,await后面跟一个promise,所以上面的代码可以写成:

const middleware = function (ctx, next) {
  console.log(1)
  next().then(() => {
    console.log(6)
  })
}

const middleware2 = function (ctx, next) {
  console.log(2)
  next().then(() => {
    console.log(5)
  })
}

const middleware3 = function (ctx, next) {
  console.log(3)
  next().then(() => {
    console.log(4)
  })
}

改成这样更好理解一些,所以流程控制的核心在于next的实现。

next要求调用队列中下一个middleware,当达到最后一个的时候resolve。这样最后面的promise先resolve,一直到第一个,这样就是洋葱模型的顺序了。

二、实现

koa-compose的实现是这样的:

functioncompose(middleware) {
  returnfunction (context, next) {
    let index = -1return dispatch(0)

    functiondispatch(i) {
      index = i
      let fn = middleware[i]
      if (i === middleware.length) fn = next
      if (!fn) returnPromise.resolve()
      try {
        returnPromise.resolve(fn(context, dispatch.bind(null, i + 1)))
      } catch (err) {
        returnPromise.reject(err)
      }
    }
  }
}

我们把一些参数检查的非核心逻辑去掉了,实现代码就上面那些。每次传入的next都是调用下一个middleware,这样是一个递归的过程,结束条件是最后一个middleware的next是用户传入的。

这里面有一些亮点:

这是一种尾递归的形式,尾递归的特点是最后返回的值是一个递归的函数调用,这样执行完就会在调用栈中销毁,不会占据调用栈.

返回的是一个Promise.resolve包装之后的调用,而不是同步的调用,所以这是一个异步递归,异步递归比同步递归的好处是可以被打断,如果中间有一些优先级更高的微任务,那么可以先执行别的微任务

compose是函数复合,把n个middleware复合成一个,参数依然是context和next,这种复合之后依然是一个middleware,还可以继续进行复合。

三、总结

Koa 中间件的实现原理,也就是洋葱模型的实现原理,核心在于next的实现。next需要依次调用下一个middleware,当到最后一个的时候结束,这样后面middleware的promise先resolve,然后直到第一个,这样的流程也就是洋葱模型的流程了。

实现的时候还有一些细节,一个是递归最好做成尾递归的形式,而是用异步递归而不是同步递归,第三就是形式上用函数复合的形式,这样复合之后的中间件还可以继续复合。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/361726.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GCN项目实战1-SimGNN

文章目录SimGNN:快速图相似度计算的神经网络方法1. 数据2. 模型2.1 python文件功能介绍2.2 重要函数和类的实现SimGNN:快速图相似度计算的神经网络方法 原论文名称:SimGNN: A Neural Network Approach to Fast Graph Similarity Computation…

2023年,即时配送迎来黄金年,其他玩家该如何“弯道超车”?

我们知道,面对如此宏达的快递行业,它的市场一直被许多人所看好。尤其近几年,随着电商、物流的发展,各互联网公司纷纷跻身这一领域。现在市面上为大家所熟知的三通一达、极兔以及顺丰等等。 除此之外,在一些细分领域&a…

AWS攻略——Peering连接VPC

文章目录创建IP/CIDR不覆盖的VPC创建VPC创建子网创建密钥对创建EC2创建Peering接受Peering邀请修改各个VPC的路由表修改美东us-east-1 pulic subnet的路由修改悉尼ap-southeast-2路由测试知识点我们回顾下《AWS攻略——VPC初识》中的知识: 一个VPC只能设置在一个Re…

劳特巴赫仿真测试工具Trace32的基本使用(cmm文件)

劳特巴赫 Trace32 调试使用教程 使用PRACTICE 脚本(.cmm) 在TRACE32 中使用PRACTICE 脚本(*.cmm)将帮助你: 在调试器启动时立即执行命令根据您的项目需求自定义TRACE32PowerView用户界面加载应用程序或符号使调试操作具有可重复性, 并可用于验证目的和回归测试 自动启动脚本…

Spring Boot系列--创建第一个Spring Boot项目

1.项目搭建 在IDEA中新建项目,选择Spring Initializr。 填写项目信息: 选择版本和Spring Web依赖: Spring Web插件能为项目集成Tomcat、配置dispatcherServlet和xml文件。此处选择的版本若为3.0.2的话会出现如下错误: java: …

【C++】文件IO流

一起来康康C中的文件IO操作吧 文章目录1.operator bool2.C文件IO流3.文件操作3.0 关于按位与的说明3.1 ifstream3.2 ofstream流插入文本3.3 ostringstream/istringstream3.4 stringstream3.5使用stringstream的注意事项结语1.operator bool 之前写OJ的时候,就已经用…

Python学习-----排序问题1.0(冒泡排序、选择排序、插入排序)

目录 前言: 1.冒泡排序 2.选择排序 3.插入排序 前言: 学过C语言肯定接触过排序问题,我们最常用的也就是冒泡排序、选择排序、插入排序……等等,同样在Python中也有排序问题,这里我也会讲解Python中冒泡排序、选择排…

MvvmLight框架入门

MvvmLight MvvmLight主要程序库 ViewModelLocator 在.netFramework环境下nuget安装MvvmLight会自动安装依赖项MvvmLightLibs库,如果在.net core环境下需要手动安装MvvmLightLibs库。 .netFramework环境下安装完成后,在ViewModel目录下具有一个 ViewMo…

page cache设计及实现

你好,我是安然无虞。 page cache的设计及实现 page cache 本质上也是一个哈希桶, 它是按照页的数量进行映射的. 当 central cache 向 page cache 申请内存时, page cache 先检查对应位置是否有span, 如果没有则向更大页去寻找一个span, 如果找到则分裂成两个. 比如…

Java基础常见面试题(五)

异常 Java 异常类层次结构图概览 : Exception 和 Error 有什么区别? Java 中,所有的异常都有一个共同的祖先 java.lang 包中的 Throwable 类。Throwable 类有两个重要的子类 Exception(异常)和 Error(错误…

DAMA-CDGA/CDGP数据治理认证考试如何报考?

DAMA认证为数据管理专业人士提供职业目标晋升规划,彰显了职业发展里程碑及发展阶梯定义,帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力,促进开展工作实践应用及实际问题解决,形成企业所需的新数字经济下的核心职业…

LocalDNS

目录 文章目录目录本节实战DNS优化1、dns 5s 超时问题解决办法2、NodeLocal DNSCache实验软件关于我最后本节实战 实战名称💘 实战:NodeLocal DNSCache-2022.7.30(测试成功)💘 实战:NodeLocal DNSCache-2023.2.21(测试成功) DNS优…

强大的内置数据结构_元组(6,)

如约而至,紧接着上一期文章,小编将会陆续把全套的Python笔记将依次发放给大家,便于大家学习Python、期末备考、巩固基础等(这几期是公众号小插曲,后期发放编程技术的话主要还是会围绕Java来展开~感谢大家支持)元组python内置数据结…

Vulnhub靶场----2、DC-2

文章目录一、环境搭建二、渗透流程三、思路总结一、环境搭建 DC-2下载地址:https://download.vulnhub.com/dc/DC-2.zip kali:192.168.144.148 DC-2:192.168.144.150 添加hosts文件:192.168.144.150 DC-2 二、渗透流程 nmap -A -…

FLV-初学总结

FLV-初学总结 从零开始仅学习了一下午的总结,本文非常稚嫩… 本文为纯初学者的学习记录,为了方便理解,内容未必严谨,可以用作纯新手的入门了解篇。本文主要的参考链接如下⬇️ 详细了解FLV:FLV官方文档(Ve…

面向对象之三大特性(二)

5. 面向对象三大特性 继承、多肽、封装 5.1 继承 类的继承与现实生活中的父、子继承关系一样。被继承的类称为父类、基类或超类,继承者称为子类。Python 继承分为:单继承和多继承(继承多个类)。 class Parent1:pass class Par…

分析称勒索攻击在非洲、中东与中国增长最快

Orange Cyberdefense(OCD)于 2022 年 12 月 1 日发布了最新的网络威胁年度报告。报告中指出,网络勒索仍然是头号威胁 ,也逐渐泛滥到世界各地。 报告中的网络威胁指的是企业网络中的某些资产被包括勒索软件在内的攻击进行勒索&…

Qt中修改界面类的类名时需要注意的几个修改点

有些时候因为一些原因,需要修改Qt中创建的界面类,需要特别注意几个修改点。 比如将test类修改为test2类 修改test.h名称为test2.h文件;修改test.cpp名称为test2.cpp文件;修改test.ui名称为test2.ui文件;修改pro文件中…

前端Docker部署方案

一、Docker容器和镜像概念 首先明确镜像和容器的概念。我们可以用 docker 构建一个镜像,这个镜像可以导入导出,用于传输,重复利用。然后如果把他 run 起来,则称为一个容器。容器是运行时,会包括运行时上下文&#xff…

Vue基础14之TodoList组件自定义事件、全局事件总线、TodoList全局事件总线

Vue基础14TodoList-组件自定义事件先改Header和Footer子组件,List先不考虑App.vueMyHeader.vueMyFooter.vue全局事件总线实现思路正规写法main.jsApp.vueStudent.vueSchool.vue总结:全局事件总线(GlobalEventBus)TodoList案例&…