上下文 APIs
具有中间软件的上下文操作的代数效应模式
通常称为"代数效应"或"文字效应",上下文APIs允许您
通过上下文访问一个操作,以方便(和
上下文)用中间软件包裹. 中间软件由
@effectionx/middleware 支持分/最大优先级
点菜.
快速启动
假设您想要定义一个日志操作, 其行为在 不同的环境。 基本表单将只记录值到控制台.
import { createApi } from "@effectionx/context-api";
export const logging = createApi("logging", {
*log(...values: unknown[]) {
console.log(...values);
},
});
export const { log } = logging.operations;
现在您可以随意使用日志 API :
import { log } from "./logging.ts";
export function* op() {
yield* log("I am in an operation");
}
以中间软件环绕
使用 around 功能可以将中间软件包围在操作周围。 这样吧
或替换
完全执行.
import { logging } from "./logging.ts";
function* initCustomLogging(externalLogger: { log(...values: unknown[]): void }) {
yield* logging.around({
*log([...values], next) {
externalLogger.log(...values);
// since we override the logger entirely, we do not invoke next
},
});
}
Middleware只在安装范围内有效——当 瞄准镜出口,中间软件被取出.
最小/最大优先级
默认, around() 注册中间软件于 "max" 优先级(最多,
与来电者相近. 您也可在 "min" 优先级( 最大,
最接近核心处理器),通过传递选项参数:
import { createApi } from "@effectionx/context-api";
import type { Operation } from "effection";
export const files = createApi("files", {
*readFile(path: string): Operation<string> {
throw new Error(`readFile("${path}") is not implemented`);
},
});
export const { readFile } = files.operations;
在您的运行时间设置中, 通过 min数字 :
import { files } from "./files.ts";
function* initNodeRuntime() {
yield* files.around(
{
*readFile([path], _next) {
return yield* nodeReadFile(path);
},
},
{ at: "min" },
);
}
max 中间器件照常包在外头 min 实值
提供实际执行情况:
import { files } from "./files.ts";
function* withLogging() {
yield* files.around({
*readFile([path], next) {
console.log(`reading ${path}`);
return yield* next(path);
},
});
}
在测试中,通过登记不同的执行交换 min数字 :
function* useTestFixtures(fixtures: Map<string, string>) {
yield* files.around(
{
*readFile([path], _next) {
return fixtures.get(path) ?? "";
},
},
{ at: "min" },
);
}
带有最大中间软件的执行命令 [M1, M2] 和中线软件
[m1, m2] 为:
M1 → M2 → m1 → m2 → core
仪器
中件可用于自动仪器:
import { fetching } from "./fetching.ts";
function* instrumentFetch(tracer) {
yield* fetching.around({
*fetch(args, next) {
try {
tracer.begin("fetch", args);
return yield* next(...args);
} finally {
tracer.end("fetch", args);
}
},
});
}
测试模拟
在不更改呼叫站点的情况下,在测试情况下进行模拟操作:
import { fetching } from "./fetching.ts";
function* useMocks() {
yield* fetching.around({
*fetch([url, ...rest], next) {
if (url === "/my-path") {
return new MockResponse("my-path");
} else {
return yield* next(url, ...rest);
}
},
});
}
范围隔离
安装在子范围中的中件不影响父母:
import { scoped } from "effection";
import { log, logging } from "./logging.ts";
function* example() {
yield* scoped(function* () {
yield* logging.around({
*log([...values], next) {
// only active inside this scope
return yield* next(...values);
},
});
yield* log("intercepted"); // middleware runs
});
yield* log("not intercepted"); // middleware does not run
}
API 密码
createApi(name, handler)
从处理器函数的名称和对象创建上下文 API 或
操作。 返回对象与 operations 财务报告和审定财务报表 around。 。 。 .
import { createApi } from "@effectionx/context-api";
import type { Operation } from "effection";
const math = createApi("math", {
*add(left: number, right: number): Operation<number> {
return left + right;
},
});
const { add } = math.operations;
function* example(): Operation<void> {
const result = yield* add(1, 2); // => 3
}
around(middlewares, options?)
在一个或多个操作周围注册中间软件 。 第二个参数控件 优先级 :
{ at: "max" }(默认)——最外,最接近呼叫者{ at: "min" }——最内向,最接近核心处理器
function* example() {
// Wrapping middleware (max, default)
yield* math.around({
*add(args, next) {
console.log("adding", args);
return yield* next(...args);
},
});
// Implementation middleware (min)
yield* math.around(
{
*add([left, right], _next) {
return left * right; // replace the core implementation
},
},
{ at: "min" },
);
}
每一个中间器件都接收到这些论点 next 函数改为
委托给下一个中件(或核心处理器). 中间软件可以:
- 通过: 调用
next(...args)并返回结果 - 变换参数: 调用
next()有不同论据 - 转换返回值: 修改什么
next()返回时 - 短路: 返回一个不调用值
next()完全没有