Design for fixing Promise serialization issue in build_eval_js.
Async functions return Promise which gets JSON.stringify'd to "{}".
🤖 Generated with [Qoder][https://qoder.com]
70 lines
1.9 KiB
Markdown
70 lines
1.9 KiB
Markdown
# 异步 Browser Script 支持设计
|
||
|
||
## 问题
|
||
|
||
`collect_lineloss.js` 的 `buildBrowserEntrypointResult` 是 async 函数,但 `build_eval_js` 生成的执行代码是同步的,导致 Promise 被 JSON.stringify 序列化为 `{}`。
|
||
|
||
**日志表现**:
|
||
```
|
||
[execute_browser_script_impl] 返回成功, payload 长度: 4
|
||
```
|
||
返回 `{}(4字符)` 而不是实际的报表数据。
|
||
|
||
## 根本原因
|
||
|
||
`callback_backend.rs` 的 `build_eval_js` 函数:
|
||
```javascript
|
||
var v=(function(){return {script}})(); // 同步执行
|
||
var t=(typeof v==='string')?v:JSON.stringify(v); // Promise -> "{}"
|
||
```
|
||
|
||
当 script 返回 Promise 时,`JSON.stringify(Promise)` 返回 `{}`。
|
||
|
||
## 解决方案
|
||
|
||
修改 `build_eval_js` 支持 Promise:
|
||
|
||
1. 用 `await` 等待 script 执行结果
|
||
2. 检测结果是否为 Promise,如果是则等待 resolve
|
||
3. 保持对同步脚本的向后兼容
|
||
|
||
## 实现细节
|
||
|
||
修改 `src/browser/callback_backend.rs` 的 `build_eval_js` 函数:
|
||
|
||
```javascript
|
||
(async function(){
|
||
try {
|
||
var v = await (function(){return {script}})();
|
||
// 等待 Promise resolve
|
||
if (v && typeof v.then === 'function') {
|
||
v = await v;
|
||
}
|
||
var t = (typeof v === 'string') ? v : JSON.stringify(v);
|
||
// ... 回调逻辑保持不变
|
||
} catch(e) {}
|
||
})()
|
||
```
|
||
|
||
关键点:
|
||
- 包装整个 IIFE 为 async
|
||
- 用 `await` 等待 script 执行
|
||
- 检测 Promise-like 对象 (`v.then === 'function'`)
|
||
- 向后兼容:同步脚本直接返回值,async 脚本返回 Promise 后被 await
|
||
|
||
## 影响范围
|
||
|
||
- `src/browser/callback_backend.rs`: 修改 `build_eval_js` 函数
|
||
- 所有 `browser_script` 类型的 skill 自动支持 async
|
||
|
||
## 测试验证
|
||
|
||
1. 运行 `cargo test` 确保现有测试通过
|
||
2. 端到端测试 `tq-lineloss-report.collect_lineloss` 返回实际数据而非 `{}`
|
||
3. 验证同步脚本(如知乎热榜)仍然正常工作
|
||
|
||
## 不在范围内
|
||
|
||
- 不修改 `wrap_browser_script`(方案 C 的做法)
|
||
- 不修改 skill 脚本本身
|