Egg这样的设计真的合理吗,把所有东西都放在ctx上面
发布于 6 年前 作者 luluzero 6466 次浏览 来自 问答

把所有东西都放在ctx上面,这样真的合理吗?

20 回复

问题太大了,具体点。(PS:依赖注入和这个不冲突,楼下答题的同学,点题了)

这不存在合理不合理,你可以指出你觉得不爽的具体的点来讨论。 总的来说我认为这个是风格问题,不是对错的事。 我个人不喜欢这个风格。

我记得koa里面ctx是每个请求都会生成一个吧

@AsJoy 是的,所以感觉有点不合理。

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

每一个请求过来都要创建一个ctx大对象。这样会造成比较多的系统开销吧

Egg ctx挂载属性时,用了很多 getter,只有去取的时候才会初始化(实例化),感觉对象并不是很大啊

@luluzero 以我们过去几年中,大规模的线上应用实践来看,实例化这块的损耗微乎其微。

另,ctx 上的都是延迟初始化的,并不是大对象。

这个 ctx 的大头其实是 request/response,就算你不用 egg 也会在用户请求的生命周期内一直存在的。举个例子,express 中其实就是每一个中间件传递的 req/res,虽然没有写成 ctx 的形式,但是它们确实在请求生命周期内一直存在;而在 koa 里就基本和 egg 一样了,毕竟 egg 其实只是往 koa 的 ctx 上加了点料。

@atian25 所以,如果整个请求的生命周期里没有调用过ctx里的插件或者service,那么这些插件和service也不会加载到ctx上了?

不放在context放哪里,你自己写的插件和service,能强行塞到洋葱中间去吗?

@luluzero Service 的 Class 会在加载期一次性被挂载到 app.serviceClasses 上,而在请求期,仅当前 Controller 调用到的 Service 才会被真正实例化。

具体可以看下 egg-core 对应的源码。https://github.com/eggjs/egg-core/blob/master/lib/loader/context_loader.js

内心 OS:请相信我们是专业的,我们有 AliNode 来帮我们实时监控着,且我们经历过多次双十一量级的顶级流量压力,如果这个东西能造成内存等方面的影响,我们早就已经优化了。

这里主要想说明 2 个点:

  1. 是延迟实例化的,你试下就知道了,加一个额外的 Service,不要调用它,在它的构造函数里面 console.log 下就知道有没有被初始化了。
  2. 即使被初始化了,一个类的内存占用,不会太大的,除非你在里面缓存了一堆字符串,实在不放心的话,你可以用 AliNode dump 下看看内存情况。

@atian25 大佬的完美答案

从项目规范上来说egg感觉确实有一些设计相对死板, 比如项目目录的约束相对死板 https://github.com/i0natan/nodebestpractices/blob/master/sections/projectstructre/breakintcomponents.chinese.md 再有service对ctx引用有些越俎代庖了, 很容易出现以下问题, 导致出现service层的代码混乱与维护困难: https://github.com/i0natan/nodebestpractices/blob/master/sections/projectstructre/createlayers.md

@1316346949 实例化后然后呢?你的 ctx 如何传递?作为每一个函数的入参?你可以自己写个伪代码试试。

@atian25 Service文件里所有service class在框架启动时就被实例化挂在到app上。在任何能取到app的地方就能娶到service。这样不需要每次请求按照cntroller映射单独实例化相应的service。只是把Service一次性实例化常驻内存,保存起来,根据请求从app上获取

@1316346949 service 要处理 ctx 上的用户信息啊,,你怎么传递给它?

@atian25 如果记得没错在创建ctx时候有一个ctx.app=this;再添加一行this.ctx=ctx。每次创建完成ctx时将他的指针挂到app上这样是否可以?在任何取到app的地方就可以拿到ctx?

@atian25 每次请求ctx创建完成后开始走中间件,从router走到controller再到service。这样通过app可以将ctx传给controller和service 。app完全变成一个常驻内存的工具箱任何东西都可以从他身上获取和挂载?controller和service可以在框架启动时就实例化完成?也就不需要ctx.service,用户少了一个心智负担,框架从头至尾app成为唯一获取信息的对象,成为一个集装箱,ctx仅仅只是koa的ctx。

@1316346949 并发啊。。。 你自己写下就知道了

大部分都是 referrence 有什么开销。

回到顶部