express/koa
函数式编程
开始前需要理解纯函数
function demo(total) {
return total + 1;
}
demo(1) // 2
不管执行多少次,只要我传入的参数是1,输出的结果都是2。
demo(100) // 101
不管执行多少次,只要我传入的参数是100,输出的结果都是101。
总结:不会产生副作用的函数。输入是值确定,输出值一定是一样的。(这个总结并不好,会让人误解。之前看到一个博客,总结的很好,现在找不到了)
本章的核心,这个也是 koa的核心
不解释版
next 代表下一个函数, next(total * 0.8) 代表执行下一个函数。每一个函数都是纯函数。
function discount(total, next) {
next(total * 0.8);
}
function express(total, next) {
next(total + 12);
}
function num(total, next) {
next(total * 10);
}
function compose(args) {
let result;
return function(ctx) {
let i = 0;
let dispatch = function (i, ctx) {
let fn;
if(i < args.length) fn = args[i];
if(i === args.length) {
result = ctx;
return;
}
return fn(ctx, dispatch.bind(null, ++i);
}
dispatch(0, ctx);
return result;
}
}
const totalMoney = compose([num, discount, express])(15);
解释版
// next 代表下一个函数, next(total * 0.8) 代表执行下一个函数。每一个函数都是纯函数。
function discount(total, next) {
console.log("discount start")
next(total * 0.8);
console.log("discount end")
}
function express(total, next) {
console.log("express start")
next(total + 12);
console.log("express end")
}
function num(total, next) {
console.log("num start")
next(total * 10);
console.log("num end")
}
function compose(args) {
let result;
return function(ctx) {
let i = 0;
// ** 重点 ** start
// 这里是递归,fn 依次是num, discount, express
let dispatch = function (i, ctx) {
let fn;
if(i < args.length) fn = args[i];
if(i === args.length) {
result = ctx;
return;
}
// fn 是 num, discount, express 函数。比如当前是 num, ctx 是 15
// bind函数调用时,除了第一个参数,其余参数将作为新函数的参数,供调用时使用。
// dispatch.bind(null, ++i) 是下一个参数 discount。递归从这里开始。
return fn(ctx, dispatch.bind(null, ++i);
}
// ** 重点 ** end
dispatch(0, ctx); // 第一步。也是洋葱模型的核心,梦开始的地方。
return result;
}
}
const totalMoney = compose([num, discount, express])(15);
// num start
// discount start
// express start
// express end
// discount end
// num end
上面的代码还可以再改进下,比如: 再调用其他函数,使用promise。这里就不展示了
KOA
核心代码在 koa/lib/application
// 洋葱模型,跟前面写的一样,但是多了 promise 这一步
app.use((ctx, next) => {
...todo
next();
...todo
})
app.listen(8000, '', ()=> {});
BFF
BFF 本质上是一种架构分层,而不是一种技术
BFF作用有哪些:
对比传统的架构,BFF的优势:
- 降低沟通成本,领域模型可以与页面 更好的解耦;
- 提供更好的用户体验,多端适配场景,数据会更加的复合交互需求。
BFF 的劣势
- 分工问题, 作为灰色地带,谁来开发, 需要明确。
- 链路复杂, 引入BFF,流程也更繁琐
- BFF 占用一部分资源
设计一个BFF 的时候,需要考虑哪些问题
- 数据处理: 数据耦合和裁剪 序列化格式转换 协议转换
- 流量处理: 请求分发 代理 削峰 熔断
- 安全: fast-gateway
Sequelize
Sequelize 是基于 Node 端的ORM,目前支持: Mysql, postgres, SQLite, SQLServer.... ORM: 帮你生成SQL,对象关系映射,映射成一个模型。
- typeORM
- typeORM 比较适用于使用了 ts 的场景
- prisma
- 在类型推导上,更加地出色
- rust 写的查询引擎
- 有一套非常成熟的 dsl
跟上一次写的 es 实战 结合起来,rollup(路由前缀) + sequelize .sequelizerc 文件设置路径(不加 .js 后缀),
npx sequelize --help 查看命令
- npx sequelize init:config , 根据.sequelizerc 自动生成文件
- npx sequelize migration:generate --name=init-powers(格式 --name=xxx-xxx) 生成 name 结尾的 js 文件
- 文件里有 up,和 down两个函数,在进行数据迁移时, async up (queryInterface, Sequelize) // 创建的表 async down (queryInterface, Sequelize) // 删除的表
/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up (queryInterface, Sequelize) {
await queryInterface.createTable('roles', {
id: { type: INTEGER, primaryKey: true },
userid: INTEGER,
roleName: STRING(30),
});
},
async down (queryInterface, Sequelize) {
await queryInterface.dropTable('roles');
}
};
- npx sequelize db:migrate 运行起来。 要装 mysql 之类的数据库,不然会报错。
我们也可以自动生成模型, 使用 sequelize-auto,网上也有,这里不写了。