https://stjy.yuque.com/jkpt/development
帐号:849476499@qq.com 密码:stjy2021
分类:nodejs
KNEX事务说明
异步async/同步await
公司的项目老框架升级历程
nodejs global的妙用
//gctx.js
//gctx.js /** * global context * @type {{}} */ let gctx = {}; gctx.error = function(msg, code) { let error = (new Error); error.code = code; error.message = msg; error.file = error.stack.split('\n')[2]; return error; }; module.exports = gctx;
//subcall.js
let subcall = {}; subcall.call = function() { //调用全局报错 //减少重复性的引用 throw gctx.error('test', 500); }; module.exports = subcall;
//index.js
const gctx = require('./gctx.js'); const subcall = require('./subcall.js'); //引入全局global context global.gctx = gctx; try { // throw gctx.error('test', 500); subcall.call(); } catch (e) { console.log(e.message, e.code, e.file); }
输出:
test 500 at Object.subcall.call (....\local_test\subcall.js:4:14)
nodejs 优雅的抛出异常
//ctx.js let ctx = {}; ctx.error = function (msg, code) { let error = (new Error); error.code = code; error.message = msg; error.file = error.stack.split('\n')[2]; return error; } module.exports = ctx;
//test.js const ctx = require('./ctx.js'); try { throw ctx.error("test", 500); } catch (e) { console.log(e.message, e.code, e.file); }
test 500 at Object.<anonymous> (F:\jy\jkpt_backend\local_test\t_error.js:9:20)
eggjs-框架, 最近入了nodejs的坑…写给新东家的新框架,基于eggjs
- app[框架主目录]
- controller[控制器]
控制器已实现路由的自动装载,只需要建立具体的控制器. 具体功能业务按需建立目录. 不要将不相干的业务揉在同一模块,同一控制器里.- admin[业务模块]
- admin.js[控制器]
- system.js[控制器]
- admin[业务模块]
- extend[扩展]
扩展目录中,可以给控制器,请求类,上下文扩展通用函数(https://eggjs.org/zh-cn/basics/extend.html) - io[socket控制器]
特别注意,静态资源,控制器请求以及io请求,都是同一个端口.通过特殊解析实现具体访问.- controller[socket控制器]
- client[socket模块]
保留模块, 后续新socket编写需要单独建立模块目录,并在具体动作中实现业务逻辑. 同样在egg的基础上补充了自动路由装载的实现.- client.js[控制器]
这个socket控制器为保留控制器, 为兼容原客户端的socket请求以及回调的特殊处理类. 所有原socket请求都会通过映射, 跳转到/app/service/client/*里的业务类进行特殊处理,并回调.原请求方式. io.emit(‘message’,{api:’login’,param:{username:’xxx’,password:’xxx’}},function(res){})新请求方式. io.emit(‘/admin/admin/login’,{param:{username:’xxx’,password:’xxx’}},function(res){})需要明确注意, socket本质上是不存在回调的. 只是socket.io-client内部和服务器实现了packetid为标志的特殊实现. 其它任何语言都没有…但然. 通过原理编写也行..原理:https://www.cnblogs.com/lightsong/p/10226940.html
- client.js[控制器]
- client[socket模块]
- extend[socket扩展]
同/app/extend - middleware[socket中间件]
- connection.js[连接中间件]
建立链接时, 可以做权限校验 - packet.js[数据包中间件]
数据请求过程中触发
- connection.js[连接中间件]
- controller[socket控制器]
- lib[工具类]
引用方式按最原始的方式引用. 不封装引用的主要目的是保留代码提示.- common[通用工具目录]
- commonHelper.js[原通用类 ]
按需要加,不需要的不要乱加进来,明确功能的.建立目录单独存放 - expressHelper.js[快递通用类]
快递一些通用的获取调用, 在各自模块中实现, 并提供统一调用. 通用类,根据类型去调用具体的帮助类, 减少过程式代码, 增加代码可读性
- commonHelper.js[原通用类 ]
- cngg[功能模块目录]
不同于业务, 一般功能模块都有其特殊实现和封装. 单独放这里. 业务功能再在业务目录里实现. 最大限度避免代码混乱. 当扩展达到一定的重复性和可用性, 可以考虑写成插件- cnggHelper.js[菜鸟裹裹帮助类]
- kdn[快递鸟目录]
- …
- common[通用工具目录]
- middleware[中间件]
个人建议称为中间处理件会相对好理解, 需要先了解下洋葱模型(https://eggjs.org/zh-cn/basics/middleware.html), 类似过滤器- commonRequest.js[通用请求中间件]
将常规请求进行前置处理, 如get和body合并到ctx.request.params中. 不区分get和post. - mwAdminUser.js[用户请求权限中间件]
实现用户的权限判断和拦截
- commonRequest.js[通用请求中间件]
- model[数据模型]
暂时使用的数据库是mongodb, 然后暂时选用的访问方式为mongose(https://mongoosejs.com/docs/guide.html), 同时提供原访问方式, 方便快速复用原代码(尽量能写成新的写成新的…别只复制粘贴…)- Admin[业务模块]
特别注意,其它目录都是小写开头, 只有数据模型的目录和类是大写开头….- Admin.js[数据模型类]
数据层可复用代码,尽量复用到数据模型. 业务层复用业务模型. 尽量减少重复代码. 如可以写一个函数load(id), 找不到直接报错. 后续通用调用即可.
- Admin.js[数据模型类]
- Admin[业务模块]
- public[静态文件]
egg-static提供静态文件访问支持, 同端口访问时. 如果路径为/public/则会自动进入该目录, 客户端和小访问量服务器可以直接使用. 大访问量, 需要实际压力测试看看. 最好还是走nginx做反向代理.- assets[静态资源目录]
- backstage[后端静态资源目录,主要是组件类封装]
复制原资源文件, 暂时按习惯的来 - upload[上传文件目录]
- router[路由配置]
- router.dev.js
路由实际配置脚本, 自动化脚本能满足基本路由情况, 如果需要特殊路由或者兼容原路由. 可以单独在这个地方再补充映射https://eggjs.org/zh-cn/basics/router.html
- router.dev.js
- schedule[计划任务]
计划任务只需要复制即可使用, 但是发现需要重启服务才会引入, 需要研究下热部署? - service[业务]
需要理解下新的设计分层, 该形式接近MVC, 但是不是MVC.常规MVC是模型,视图,控制器, egg 结构层是 数据层(model), 控制器(controller), 业务(service), 视图(view), 控制器只做权限以及参数校验, 具体功能封装到业务层中. 主要目的是实现代码的高复用性.如登陆,封装成service.user.login(username,password), 后续任何地方都是调用这个业务, 即可实现登陆. 同时后续的单元测试, 主要是测试业务类.同时, 业务需要以抛出异常的形式代替返回值判断, 并再最外层进行异常处理. 可大大增加代码的可读写以及编写. 避免没必要的各种判断- admin[业务模块]
- adminService.js[业务类]
结构类似控制器, 全是只为处理具体业务代码
- adminService.js[业务类]
- client[保留模块]
原客户端的io调用使用的方式和egg-socket不一样. 未避免冲突, 单独配置一个io路由,并将原请求动作全部映射到这里的具体业务动作. 同时兼容了socket.io-client的回调- enterpriseService.js[原客户端所有socket调用]
- admin[业务模块]
- view[视图]
所有页面文件以*.ejs做后缀, webstorm,vscode等格式化和开发过程中<% %>会有代码提示, 会极大的提高开发效率, 测试过程中, 也可以考虑页面代码在<%%>中测试再贴回去. 页面保存是实时更新的. nodejs其它功能模块修改在ssd的情况下, 依然需要4,5 秒的重启- admin[模块目录]
- site[控制器目录]
- login.ejs[登陆页面]
页面对应具体的控制器
- login.ejs[登陆页面]
- site[控制器目录]
- layout[通用页面组件]
- layout.ejs[图层]
包含常用的静态资源文件引入, 控制器里渲染页面时, 图层会包裹具体的页面代码, 可以方便全局性调整. 对于可复用的页面组件, 都可以考虑封装成*.ejs或者作成vue组件, 按需要来
- layout.ejs[图层]
- 200.ejs[通用消息提示页面]
- 500.ejs[通用错误消息提示页面]
- admin[模块目录]
- router.js[路由脚本]
用于引用/app/router里的实际路由脚本, 路由脚本在egg的基础上加了自动配置, 只需要复制或新增控制器, 就会自动添加路由
- controller[控制器]
- test[单元测试目录]
- local_test[自己编写的框架外的测试脚本]
- io[socket测试脚本]
配置了一个测试脚本,模拟客户端所有的websocket调用 - t_mongose.js
测试mongose相关https://mongoosejs.com/docs/guide.html
- io[socket测试脚本]
- cache[缓存目录]
如果使用缓存, 则目标缓存会生成到该路径下, 如果服务器有多节点. 缓存必需存放到redis或数据库, 不能配置单机的fs或内存缓存. 除非是代码或页面类缓存,视具体情况选择 - config[配置目录]
- locale[翻译目录]
- zh-CN.js[翻译语言配置脚本]
egg-validate的翻译,需要在这个地方进行配置
- zh-CN.js[翻译语言配置脚本]
- config.default.js[默认配置]
- config.dev.js[具体环境配置脚本]
可根据启动命令不同,加载不同配置文件,方便测试 - plugin.js[插件配置]
框架使用插件,必须在这个地方启用, 然后如果有特殊参数配置,在/config/config.default.js里进行详细参数配置. egg默认启用的插件需要到/node_modules/eggjs 里进行查看.
- locale[翻译目录]
- logs[日志目录]
- test_egg[项目名]
- common-error.log[常规日志]
- egg-agent.log[agent日志]
- egg-schedule.log[计划任务日志]
- egg-web.log[egg内部日志]
- test_egg[项目名]
- package.json[配置文件]
- 启动命令
- 启动开发环境:npm run dev
- 实际脚本:egg-bin dev –sticky –port 7001
- 启动生产环境:npm run start
- 实际脚本:egg-scripts start –daemon –sticky –port 7001
- 启动开发环境:npm run dev
- 启动模式
- 框架是以 Cluster 方式启动的,而 socket.io 协议实现需要 sticky 特性支持,否则在多进程模式下无法正常工作。
- 注意事项
- 最好指定端口, 否则开发工具崩溃后, 重新运行, 会被重新分配端口, 避免带来不必要的问题
- 启动命令
- 框架保留问题, 需要找时间进行优化
- 框架文件过多(超过3w+文件…)
- 优化方向:减少不必要的扩展.
- 重启速度需要再进行研究优化,在ssd的情况下, 重启服务需要大概4,5秒, 较影响开发, 不过配合调试模式, 可以弥补.
- 优化方向:考虑单独写个启动脚本, 抛弃一些特性来实现热更新, 具体再观望看看别人有没有其它实现. 尽可能实现修改后马上可见.
- 页面组件化
- 优化方向:无
- 还在学习和了解中.
- 优化方向:无
- 框架文件过多(超过3w+文件…)