---
# System prepended metadata

title: 使用 Effect 提升前端應用程式的穩定性與可維護性 - 彭勝宇
tags: [JSDC2025]

---

# 使用 Effect 提升前端應用程式的穩定性與可維護性 - 彭勝宇

{%hackmd @JSDC-tw/B1loEcwJZl %}
###### tags: `JSDC2025`

Slido：https://app.sli.do/event/pG5n1iyWYfa6TEpoLA7DA6
Effect 的官網: https://effect.website
講者寫的教學文章: https://ithelp.ithome.com.tw/users/20111802/ironman/8800
互動式的 Effect 教學： https://effect.kitlangton.com
簡報：
- [web 版](https://dansnow.github.io/talks/2025-11-29-jsdc/)
- [pdf 版](https://github.com/DanSnow/talks/blob/main/slides/2025-11-29-jsdc/%E4%BD%BF%E7%94%A8%20Effect%20%E6%8F%90%E5%8D%87%E5%89%8D%E7%AB%AF%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F%E7%9A%84%E7%A9%A9%E5%AE%9A%E6%80%A7%E8%88%87%E5%8F%AF%E7%B6%AD%E8%AD%B7%E6%80%A7%20-%20Slidev.pdf)


> 開始做筆記

Effect 很少人聽過，更不用說用過的人了

2020 出，2024 - 2025 12K Starts
講者在發哥 David Peng
https://github.com/danshow


## Type-Safe Error Handling
Demo Code 潛在的錯誤
```ts=
function getData(id: string) {
    const r = await fetch(`/items/${id}`); // Fetch 網路問題
    return r.json() // JSON 型別不明
}
```

嘗試 Handling, 程式碼大暴增，這裡只列部分 slide
```ts=
invariant(id.length > 0, 'id 長度');

throw new Error();
```
- 複雜度


### Effect Type
```ts=
// Original: Effect<A, E, R>
Effect<Success, Error, Requirements>
```
設置檢查點

上述範例改寫
```ts=
Effect.fn('fetchDetail')(function *(id: string) {
   const res = yield* Effect.tryPromise({
       try: () => fetch(`/items/${id}`);
       catch: () => throw
   })
});
```
> 重新發現 Generator 的好

async + await 放到 JS Runtime
generator 放到 code 的外面，丟出去然後從 yield 拿回來

```ts=
function *fetchDetail() {
    const a = yield *getXXX();
}
Effect.run(
    fetchDetail(),
    (error) => handleError(error)
);
```

Promise 的短處：
1. 無法標示可能發生的錯誤
2. API 設計 -> 錯誤碼多，non 200 + network

### Schema 定義型態
```ts=
const ItemSchema = Schema.Struct({
    id: Schema.String,
});

type ItemDetail = typeof ItemSchema.Type;
```

## Effect 畫藍圖
```ts=
pRetry(
    async () => {
         const result = await flaskyAPI();  
    },
    {
        retries: 3,
        minTimeout: 500,
        factor: 2
    }
)
```

Effect
```ts=
Effect.tryPromise(

),
Effect.retry({
    times: 3,
    
})
```

```ts=
Effect.all(
    [
        fetchUser(1),
    ],
    {
        concurrency: 'unbounded'
    }
)
```
Q&A: 包起來，要怎麼平行地處理 yield? Effect runtime 也可以處理

> function programming 的延伸

強調 "要做什麼"，自由組裝

### Dependencies Injection
`Effect.provideService`

### Demo
Trello
- 從[TypeSense](https://typesense.org/)不同抓取條件
- 一次抓多個
- 大量平行請求
- 網路不穩定處理

背後會幫你組合起來

案例分享：瀏覽器資料遷移
- 本機資料與 Server 資料會重複生成很多
- 累積了不少資料
- 決定一次將 Client 資料傳上 Server，資料量過大

`withProgressRecord` 追蹤資料走向

`Effect.addWith` 一次收集全部

## 導入 Effect 遇到的問題
- Learning Curve
    - New Concepts to be used to
    - Resolve:
        - From small side project
        - Code Review to share knowledge

- 擅長
    - 複雜錯誤
    - 異步
        - Retry
        - Concurrency
    - 資源管理
    - 依賴注入
    - 類型安全

# Q & A

- 有互動教學：https://effect.kitlangton.com

午安，想知道 Effect 跟 RxJS 有什麼差異呢？
- RxJS 處理 Steam

前端資料容易被後端資料架構限制，要怎麼導入
- 先用熟悉的方式

佔空間？
- 看你怎麼使用
    - 開發電商會有固定流程
    - 若遇到複雜狀況可以考慮

vs fp-ts
- fp-ts 作者加入 Effect 了！

Effect 推薦使用 fp 嗎？class
- 的確鼓勵使用 fp，除了部分 class

> 聊天區

---

{%hackmd @JSDC-tw/jsdc2025_sponsor %}