You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让libuv Timer实现异步运行?QuickJS setTimeout同步问题排查

问题排查与修复

你的核心问题是事件循环触发时机错误,直接导致JS同步代码被阻塞,异步逻辑完全失效。

错误原因

你在setup_setTimeout函数里启动定时器后立刻调用了uv_run(loop, UV_RUN_DEFAULT)——这个模式会让libuv事件循环一直运行,直到所有事件句柄(handle)都被关闭。这就导致JS代码执行到setTimeout时直接进入阻塞,必须等定时器触发完成后,才会继续执行console.log("End"),完全违背了异步逻辑的预期。

修复步骤

1. 调整事件循环触发时机

uv_run绝对不能在setTimeout内部调用,必须让JS引擎先完整执行所有同步代码(也就是Start、End的输出),等同步代码全部跑完后,再启动libuv事件循环处理异步任务。

2. 修正setup_setTimeout实现

移除函数内的uv_run调用,只负责初始化和启动定时器:

int setup_setTimeout(uv_loop_t *loop, int delay) {
    uv_timer_t* timer_req = (uv_timer_t*)malloc(sizeof(uv_timer_t));
    // 绑定延迟值到timer_req的data字段,方便回调使用(如果需要)
    timer_req->data = (void*)(intptr_t)delay;
    
    uv_timer_init(loop, timer_req);
    // 第三个参数是延迟时间(毫秒),第四个是重复间隔(0表示只执行一次)
    uv_timer_start(timer_req, timerCallback, delay, 0);
    
    // 这里不要调用uv_run!
    return 0;
}

3. 完善定时器回调的内存管理

为了避免内存泄漏和段错误,回调里要正确清理定时器资源:

void timerCallback(uv_timer_t* handle) {
    // 执行QuickJS的回调逻辑(调用你绑定的JS函数)
    std::cout << "Timeout has run" << std::endl;
    
    // 停止定时器并关闭句柄
    uv_timer_stop(handle);
    uv_close((uv_handle_t*)handle, [](uv_handle_t* h) {
        // 关闭完成后释放内存
        free(h);
    });
}

4. 调整主流程逻辑

主程序必须按以下顺序执行:

int main() {
    uv_loop_t *loop = uv_default_loop();
    
    // 1. 初始化QuickJS环境,加载并执行JS代码
    // (此步骤会先输出Start → 调用setTimeout注册定时器 → 输出End)
    
    // 2. JS同步代码执行完毕后,启动libuv事件循环
    uv_run(loop, UV_RUN_DEFAULT);
    
    std::cout << "*****This one runs after 5 second*******" << std::endl;
    
    return 0;
}

修复后的输出顺序

修正后,程序会按异步逻辑预期输出:

Start
End
Timeout has run
*****This one runs after 5 second*******

内容的提问来源于stack exchange,提问作者Anurag Vohra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 19:05:31