⑭ 轻量自研兜底 + 外挂真引擎提速:「够用自己写,难了就引外挂」
目标:学一个实用的取舍思维——当一项功能既不想给用户背太重依赖、又想要高性能时,用两个档位解决:平时用自研的轻量版兜底(满足基本功能),复杂/吃性能的场景再外挂一个真实引擎去提速。yt-dlp 跑网站下发的 JS 时,就同时用「纯 Python 迷你解释器」和「Node/QuickJS 真实运行时」两档。
呼应文档 ⑬(硬依赖与可选降级)。⑬讲"能力分级、坏了降级",这篇讲"从自研到外挂的能力升级怎么分层"。
一、项目里的业务例子:必须"执行 JS"才能下视频
先说清楚 yt-dlp 为什么需要这个。
- YouTube 这类网站,视频下载地址不是直接给的,而是藏在一段 JS 代码里。
- 你得先执行这段 JS,算出签名参数,才能拼出真正能下载的 URL。
于是 yt-dlp 必须"跑 JS"。但这就撞上一件麻烦事:
跑 JS 最省事是装一个 JS 引擎(比如 Node.js)。可一旦强制要求用户装 Node,yt-dlp 就再也"轻不起来了"——很多用户只是想过个剪贴板链接,凭什么要装一个运行时?
这逼出一个经典问题:既不想要重型依赖,又想要 JS 执行能力,怎么办?
二、解法:拆成「两档」,按需启停
yt-dlp 的答案是准备两个档位,平时用轻的、必要时用重的:
| 档位 | 是什么 | 什么时候用 | 代价 |
|---|---|---|---|
| 第一档:自研轻量 | 手写的纯 Python"迷你 JS 解释器" | 绝大多数普通场景 | 慢一点,但零依赖 |
| 第二档:外挂真引擎 | Node / Bun / Deno / QuickJS | 复杂的 JS challenge | 快,但要装运行时 |
默认 -------------------------------------> 用户装了 Node 之类的运行时
纯 Python 迷你解释器(兜底) 真实 JS 引擎(提速)
谁也跑得动、零依赖 复杂 JS 也快
[!important] 核心思路:轻量版负责"人人都能跑",外挂版负责"复杂场景跑得快"。两个档位并存在代码里,由环境自动决定用哪个。
三、为什么非得"自研一个解释器",不能直接引轮子
你可能想:何必自己写 Python 解释器,直接引现成的 JS 引擎库不行吗?
这正是关键取舍——yt-dlp 不是没想过,而是"不需要多强":
- 它要执行的 JS,其实只是一个签名函数,代码量很小、逻辑很简单;
- 为自己写一个"能看懂并执行这种简单 JS 的迷你解释器",复杂度可控,还彻底摆脱了任何第三方依赖;
- 换句话说:需求只有"算个签名"这么小,就没必要为一个完整 JS 引擎付出依赖和体积的代价——"够用就行"。
而真遇到复杂场景(比如 YouTube 的 challenge 变种,纯 Python 跑不动/太慢),那就不硬撑,外挂 Node/QuickJS 真引擎接着干。
这个"够用自己写,难了才引外挂"的两档切换,比一味求全或一味从简都聪明——普通用户零负担,高级用户有性能。
四、这套思维在哪都能用
| 你的场景 | 轻量自研档(人人可用) | 外挂真引擎档(复杂提速) |
|---|---|---|
| 公式/表达式计算 | 自写简单解析器 | 引成熟的表达式引擎 |
| 模板渲染 | 自写 mini 模板 | 引完整的模板系统 |
| 正则/规则匹配 | 简单字符串匹配 | 引完整规则引擎 |
| 代码执行 | 沙箱用小实现 | 外挂真实解释器 |
| 数据库 | 内存里自存小索引 | 接到完整数据库 |
通用规律:当你"既要能力、又要轻量"时,别二选一——做成两档:
- 常见的基础请求 → 自研轻量版兜底(零依赖、人人可跑)
- 少见的复杂请求 → 外挂真实引擎提速(多装一次,物有所值)
五、核心金句
别因为"偶尔要复杂能力"就让所有人背上重依赖。 拆成两档:轻量版自研兜底满足基本需求(零依赖、人人能跑),真实引擎外挂应对复杂场景(多装一次,换性能)。由环境/场景自动切换——普通用户零负担,高级用户有性能。
六、在 yt-dlp 里对应哪里(供回溯)
- 轻量档(自研纯 Python 解释器):
yt_dlp/jsinterp.py - 外挂档(外部运行时抽象 + provider):
yt_dlp/utils/_jsruntime.py、yt_dlp/extractor/youtube/jsc/ - 业务触发案例:
yt_dlp/extractor/vk.py(VK 的 salt 签名用迷你解释器算) - 学习库 → [[Support-Layer-JS-Plugins-Utils]]
七、一句话带走
一项功能"不是太复杂、但又不想让用户背重依赖"时,别硬造也别硬引。学会两个档位:自研轻量版兜底保证任何人零依赖就能跑,外挂真引擎在复杂/吃性能时才上。yt-dlp 就是这么处理"必须跑 JS、却不想逼用户装 Node"的——普通用户零负担,复杂场景才有性能。