76 # koa 上下文的实现原理

news2024/12/28 19:25:12

上一节实现了 koa 基本逻辑实现以及属性的扩展,下面继续实现上下文的实现

ctx 跟 proto 的关系

ctx.__proto__.__proto__ = proto

MDN:defineGetter

备注: 此特性已弃用,建议使用对象初始化语法或 Object.defineProperty() API 来定义 getter。该方法的行为只针对 Web 兼容性进行了规定,在任何平台上都不需要实现该方法。它可能无法在所有地方正常工作。

MDN:defineSetter

备注: 此特性已弃用,建议使用对象初始化语法或 Object.defineProperty() API 来定义 setter。该方法的行为只针对 Web 兼容性进行了规定,在任何平台上都不需要实现该方法。它可能无法在所有地方正常工作。

  • __defineGetter__() 方法将一个对象的属性绑定到一个函数上,当该属性被访问时,该函数将被调用。
  • __defineSetter__() 方法将一个对象的属性绑定到一个函数上,当该属性被赋值时,该函数将被调用。
__defineGetter__(prop, func)
__defineSetter__(prop, func)

以后使用 ctx 变量时,会很少使用原生的 req 和 res,一般使用的都是 request,reponse,或者直接使用的方式。

下面代码实现:

application.js

const EventEmitter = require("events");
const http = require("http");
const context = require("./context");
const request = require("./request");
const response = require("./response");

console.log("kaimo-koa---->");

class Application extends EventEmitter {
    constructor() {
        super();
        // 防止多个实例共享 context request response 需要进行拷贝
        this.context = Object.create(context);
        this.request = Object.create(request);
        this.response = Object.create(response);
    }
    use(callback) {
        this.callback = callback;
    }
    // 创建一个上下文
    createContext(req, res) {
        // 每次请求都应该是一个全新的 context,需要拷贝
        let ctx = Object.create(this.context);
        // 上下文中有一个 request 对象,是自己封装的
        ctx.request = Object.create(this.request);
        // 上下文中还有一个 req 属性 指代的是原生的 req,自己封装的 request 对象上有 req 属性
        ctx.req = ctx.request.req = req;
        // 上下文中还有一个 response 对象,是自己封装的
        ctx.response = Object.create(this.response);
        // 上下文中还有一个 res 属性 指代的是原生的 res,自己封装的 response 对象上有 res 属性
        ctx.res = ctx.response.res = res;
        return ctx;
    }
    handleRequest(req, res) {
        const ctx = this.createContext(req, res);
        this.callback(ctx);
    }
    listen(...args) {
        const server = http.createServer(this.handleRequest.bind(this));
        server.listen(...args);
    }
}

module.exports = Application;

上下文 context.js

const proto = {
    // get url() {
    //     console.log(this.__proto__.__proto__ === proto);
    //     return this.request.url;
    // },
    // get path() {
    //     return this.request.path;
    // }
};
// 上面一个一个写比较麻烦,可以使用 __defineGetter__ 去实现代理
function defineGetter(target, key) {
    proto.__defineGetter__(key, function () {
        return this[target][key];
    });
}

function defineSetter(target, key) {
    proto.__defineSetter__(key, function (value) {
        this[target][key] = value;
    });
}

defineGetter("request", "url"); // ctx.url => ctx.request.url
defineGetter("request", "path"); // ctx.path => ctx.request.path
defineGetter("request", "query"); // ctx.query => ctx.request.query

defineGetter("response", "body"); // ctx.body => ctx.response.body
defineSetter("response", "body"); // ctx.body => ctx.response.body

module.exports = proto;

response.js

const response = {
    _body: "",
    get body() {
        return this._body;
    },
    set body(value) {
        this._body = value;
    }
};

module.exports = response;

测试 demo.js

const Koa = require("./kaimo-koa");
const app = new Koa();

app.use(async (ctx, next) => {
    ctx.body = "Hello kaimo Koa";
    console.log("url---->", ctx.request.url);
    console.log("path---->", ctx.request.path);
    console.log("query---->", ctx.request.query);
    // ctx.__proto__.__proto__ === proto
    console.log("ctx.url---->", ctx.url);
    console.log("ctx.path---->", ctx.path);
    console.log("ctx.query---->", ctx.query);
    // ctx.body => ctx.response.body
    console.log("ctx.response.body---->", ctx.response.body);
});

app.on("error", (err) => {
    console.log(err);
});

app.listen(3000);

启动服务,访问 http://localhost:3000/kaimo?a=313

nodemon demo.js

在这里插入图片描述

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

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

相关文章

《职场情绪稳定:内在的力量与策略》

近期发生的新闻热点,如大规模裁员、创业公司倒闭、公共卫生事件等,让公众更加关注稳定情绪和心理健康的问题。在职场中,我们常常遇到各种挑战和压力,如何保持稳定的情绪成了一个重要的话题。 首先,让我们分享一些工作中…

RecyclerView的smooth scroller -- 诸多案例

作者:snwrking 最近碰到好几个使用LinearSmoothScroll(下方简称为LSS)的场景, 让我对这个类的了解更加进一步, 所以分享在这, 希望对有需要的同学有所帮助. 我个人不太喜欢太理论的东西, 所以整篇文章几乎全是我做过的案例, 也方便也有类似需求的同学对号入座地取用…

【用unity实现100个游戏之8】用Unity制作一个炸弹人游戏

文章目录 前言素材开始一、绘制地图二、玩家设置三、玩家移动四、玩家四方向动画运动切换 五、放置炸弹六、生成爆炸效果七、墙壁和可破坏障碍物的判断八、道具生成和效果九、玩家死亡十、简单的敌人AI十一、虚拟摇杆 待续源码完结 前言 我们将在这个视频中,学习如…

Oracle 遍历变量游标

背景 由于我们的数据库系统中的游标特别多,DBA让我们优化,减少游标的使用。 电脑系统:windows数据库:Oracle数据库图形化界面工具:Toad,DBeaver(我測試的時候用的)记录日期:2023-09-04 具体实…

macbookpro怎么删除软件没有鼠标

macbookpro怎么删除软件没有鼠标,macbookpro触摸板可以替代鼠标进行操作。左右键功能与鼠标相同,可用于执行删除操作。此外,还可以利用键盘上的Delete键来删除选中的文件。 删除软件方法 方法1、打开应用程序,键盘按住control,加点…

解决微信小程序recycle-view使用百分比单位控制宽高时出现的内容溢出问题

recycle-view是微信小程序官方推出的一个经过优化的长列表组件,但是在使用百分比单位控制高宽时有个内容溢出问题,虽然它提供了height和width的参数可以设置宽高,但每次写列表都需要去js里获取宽高并设置是较为麻烦的,所以现在来着…

Vue 3 基础(二)基础 1

API 参考 1、创建一个 Vue 应用 1.1 应用实例 每个 Vue 应用都是通过 createApp 函数创建一个新的 应用实例: import { createApp } from vueconst app createApp({/* 根组件选项 */ })1.2 根组件 我们传入 createApp 的对象实际上是一个组件,每个…

uni-app 之 图片

uni-app 之 图片 获取图片 v-bind 动态绑定 image.png <template><view><view>--- 获取图片1 ---<image src"../../static/img/tabbar_home1.png"></image></view><view>--- 获取图片2 v-bind 动态绑定---<image v-bi…

SolVES4.1学习1——安装与使用教程

1、下载并安装 SolVES 4版本是QGIS插件&#xff0c;但实际使用过程中发现在最新版的QGIS安装该插件过程中&#xff0c;会报错或异常。因此需安装特定版本的软件。共需安装如下图软件及Java环境等。 根据官方文档安装好后&#xff0c;可以进行相关操作。 2、设置QGIS环境 QG…

AutoSAR配置与实践(基础篇)3.7 BSW的WatchDog功能(下)

AutoSAR配置与实践(基础篇)3.7 BSW的WatchDog功能(下) BSW的WatchDog功能(下)一、WDG和其他模块交互BSW的WatchDog功能(下) ->返回总目录<- 一、WDG和其他模块交互 模块交互 看门狗模块由WdgM统一管理,这里围绕WdgM模块分析与其他模块交互。通过交互的说明,可以…

css画箭头图标放标题前面,旋转,border的单个边框设置

CSS边框属性_css border dotted_小张biubiu的博客-CSDN博客 你还不知道css的旋转效果怎么实现&#xff1f;来这里看看吧_css旋转效果_我糖呢的博客-CSDN博客 .sub-title{position: relative;margin-left: 59px;& span{color: #1CDBFE;};& span::before{content: "…

MyBatis-Plus深入 —— 条件构造器与插件管理

前言 在前面的文章中&#xff0c;荔枝梳理了一个MyBatis-Plus的基本使用、配置和通用Service接口&#xff0c;我们发现在MyBatis-Plus的辅助增强下我们不再需要通过配置xml文件中的sql语句来实现基本的sql操作了&#xff0c;不愧是最佳搭档&#xff01;在这篇文章中&#xff0c…

ping: www.baidu.com: Name or service not known 写了DNS还是不行

环境描述&#xff1a;ESXI平台上&#xff0c;一台Centos7虚拟主机。 问题描述&#xff1a;平台上的其他的虚拟机可以正常ping通&#xff0c;就这台ping IP地址可以通&#xff0c;ping域名解析失败。 排查过程&#xff1a; 1、检查网卡配置文件和/etc/resolv.conf配置文件是否…

【综述+3D】基于NeRF的三维视觉2023年度进展报告(截止2023.06.10)

论文&#xff1a;2003.Representing Scenes as Neural Radiance Fields for View Synthesis 官方网站&#xff1a;https://www.matthewtancik.com/nerf 突破性后续改进&#xff1a; Instant Neural Graphics Primitives with a Multiresolution Hash Encoding | 展示官网&#…

K8S的介绍和架构

仅供入门 K8S的介绍和架构 一. 什么是kubernetes二、Kubernetes架构和组件 2.1 核心组件 2.1.1 Kubernetes Master控制组件&#xff0c;调度管理整个系统&#xff08;集群&#xff09;&#xff0c;包含如下组件: a、Kubernetes API Serverb、Kubernetes Schedulerc、Kubernet…

【前端】CSS-Grid网格布局

目录 一、grid布局是什么二、grid布局的属性三、容器属性1、display①、语句②、属性值 2、grid-template-columns属性、grid-template-rows属性①、定义②、属性值1&#xff09;、固定的列宽和行高2&#xff09;、repeat()函数3&#xff09;、auto-fill关键字4&#xff09;、f…

Vue指令之战:v-if vs. v-show -你应该使用哪一个?

在Vue.js中&#xff0c;条件渲染是一项常见任务&#xff0c;而v-if和v-show是两个最常用的指令。这两个指令在实现方式上有所不同&#xff0c;对于开发者来说选择正确的指令可能具有挑战性。本文将深入探讨Vue 2和Vue 3中的v-if和v-show指令的区别&#xff0c;并结合实际应用场…

Linux的命令

Linux的命令分为四个类型&#xff1a;文件操作命令、系统操作命令、文本处理命令和网络操作命令。下面简单介绍一下常用的Linux命令&#xff1a; 文件操作命令 ls&#xff1a;列出目录下的所有文件和目录。 cd&#xff1a;切换当前目录。 mkdir&#xff1a;创建一个新目录。…

<图像处理> 可分离滤波器核

可分离滤波器核 空间滤波器核是一个二维矩阵&#xff0c;若它能够表示为两个一维矩阵的乘积时&#xff0c;则表示该滤波器核是可分离的。 例如&#xff0c;一个3x3的核&#xff0c; w [ 1 1 1 1 1 1 1 1 1 ] w\begin{bmatrix} 1 & 1 & 1\\ 1 & 1& 1\\ 1 &am…