V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Cyron
V2EX  ›  Next.js

NextJS 可以在 route handler 中使用 setTimeOut 吗

  •  
  •   Cyron · 209 天前 · 1157 次点击
    这是一个创建于 209 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在用 NextJS 写 API 时,想要实现一个场景:用户操作成功后,服务器在 2s 后执行一个逻辑。

    下面用 kv 做个示例:

    import { kv } from "@vercel/kv";
    
    export async function GET() {
      let page1 = await kv.get("page:1");
    
      setTimeout(() => {
        kv.incr("page-visit:1");
      }, 2000);
    
      return Response.json({ data: page1 });
    }
    
    export const runtime = "edge"; // 尝试过 nodejs 效果一样
    export const fetchCache = "force-no-store";
    

    其中 incr 在本地可以正常执行,但在 Vercel 上部署时会发生:

    • timeout=10ms 时,可以正常执行 incr
    • timeout=2000ms 时,本次 API 调用不会执行 incr ,但会在下次调用时执行上一次的 incr

    我的猜测是:本地 node 是守护进程,所以计时器不会被卸载掉,incr 正常执行;而 Vercel 上是 Serverless Function ,10ms 内 CPU 分配还在就会执行 incr ,2000ms 时 CPU 已经不分配了就不会执行 incr

    我只是想薅 Vercel 的羊毛,请教大家如何才能做到延迟调用

    4 条回复    2024-05-04 19:07:41 +08:00
    moooooooo
        1
    moooooooo  
       209 天前
    你这个 setTimeout 是异步的。用 Promise 包一层变成同步使得 get 里的代码依次执行就行了
    Cyron
        2
    Cyron  
    OP
       206 天前
    @moooooooo #1 我就是想异步,让 response 先返回
    rocmax
        3
    rocmax  
       203 天前
    默认 Timeout:
    edge: 25s
    node: Hobby plan 10s
    https://vercel.com/docs/functions/runtimes#max-duration

    2s 不至于触发 timeout ,setTimeout 把回调函数入栈后应该是会被执行的。你观察到的现象是不是第一次后台执行完了第二次访问才看到更新后的状态?因为按道理第二次执行会添加一个新的计时器。

    你的需求可以考虑用 streaming 实现,先创建 stream 发你想发的 response ,等 2s 后处理完成后再发送更新后的结果&关闭 stream 。
    Cyron
        4
    Cyron  
    OP
       200 天前 via iPhone
    @rocmax 我写过 streaming api ,这个和 timeout 确实没关系,我给的代码片段你可以试一下
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4721 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 09:50 · PVG 17:50 · LAX 01:50 · JFK 04:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.