821 words
4 minutes
Effect 入门教程:4.控制副作用 - 像值一样处理 Effect

让我们退一步思考。console.log 有什么问题?为什么 effect 的急切执行是不好的?我们从 effect 增加的复杂性中获得了什么好处?

我们的目标是控制任何 effect,就像我们控制值一样

  • 将 effect 存储到变量中
const value = 10; // ✅

const value = console.log("Hello"); // ⛔️
  • 重构 effect 而不改变程序的含义
const main = () => {
  // ...

  console.log("Hello"); // ⛔️ 如果你把这个移出去,`main` 就改变了,它不再打印了!

  // ...
}
  • 使它们具有确定性(易于测试)
/// ✅ 用相同的 `n` 调用这个函数总是给出相同的结果
const main = (n: number) => n * 2;

/// ⛔️ 我们如何测试这个?
const main = () => {
  makePayment();
}

我们所说的 “effect” 是指修改系统中某些内容的操作:

  • 写入数据库(修改存储的数据)
  • 打开弹窗(修改 UI)
  • 在控制台打印(修改控制台状态)
const print = console.log("Hello");

print 并没有存储日志操作console.log 已经”做了”某些事情,它只是返回了空值(void)。

如果 print 只是描述*“将要在控制台打印的某些内容”*,那就太好了。

这将允许我们重用 print,将其存储到数组中,作为函数参数传递,这些都是像 console.log 这样的语句无法做到的:

const print: Print = // 想象 `Print` 存储"将要在控制台打印的某些内容"


// ✅ 我们可以将"打印"存储在数组中
const printingArray = [print, print, print];


// ✅ 我们可以将"打印"传递给函数
const printIfTrue = (check: boolean, toPrint: Print) => {
  if (check) {
    toPrint.run(); // 👈 这里是我们实际在控制台打印的地方
  }
}

//                👇 `Print` 是一个值
printIfTrue(true, print);

这在 console.log 中是无法做到的:

const printingArray = [
  console.log("Hello"),
  console.log("Hello"),
  console.log("Hello"),
];

const printIfTrue = (check: boolean, toPrint: any) => {
  /// ...
};

printIfTrue(true, console.log("Hello"));

猜猜运行这段代码会发生什么?

每次我们定义 console.log 时,打印操作就会被执行。这是因为 console.log急切的:“定义”和”执行”之间没有区别。

当你输入 console.log 的那一刻,打印就被执行了。

想象一下,如果不是 console.log 而是 makePayement 😳

如何控制 effect#

我们可以通过将 console.log 包装到函数中来”控制”它:

const print = () => console.log("Hello");

这使得 console.log 成为一个值。因此我们可以像之前使用 Print 一样使用它:

// 👇 通过将 effect 包装到函数中将其转换为值
type Print = () => void;
const print: Print = () => console.log("Hello");


// ✅ 我们能够再次将"打印"视为值
const printingArray = [print, print, print];

const printIfTrue = (check: boolean, toPrint: Print) => {
  if (check) {
    toPrint();
  }
}

printIfTrue(true, print);

这样可以工作!它只会打印一个 Hello,这是由执行 printIfTrue 引起的:


这是 effect 中几乎所有内容的关键方面:

import { Console } from "effect";

const print = Console.log("Hello");

const printingArray = [print, print, print];

const printIfTrue = (check: boolean, toPrint: Effect<void>) => {
  if (check) {
    Effect.runSync(toPrint);
  }
}

printIfTrue(true, print);

Effect 允许控制 effect 并将它们视为值

通过使用值而不是语句,我们重新获得了组合、重构和测试的能力。

再次强调,Effect 只是描述你的程序将要做什么。你需要显式地运行它才能发生任何事情。

Effect 入门教程:4.控制副作用 - 像值一样处理 Effect
https://0bipinnata0.my/posts/course/effect-beginners-complete-getting-started/setting-up-the-project/controlling-effect-like-values/
Author
0bipinnata0
Published at
2025-08-30 12:56:25