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

为何Server Actions无法并发执行?附场景示例与优化疑问

问题描述

给定以下函数:

async function printAB() {
  console.log("A");
  await new Promise((resolve) => setTimeout(resolve, 1000));
  console.log("B");
}

async function f() {
  printAB();
  printAB();
}

通常调用f()的预期输出为:

A
A
B
B

这是因为console.log('A')语句可与后续的超时操作并发执行。无论函数同时运行在服务端(Server Actions或服务端组件中定义)还是客户端,都能得到该结果。但如果printAB是Server Actions,而f是客户端组件中的函数,输出则变为:

A
B
A
B

请问该现象的原因是什么?同时调用多个此类Actions会导致性能下降,是否有规避方法?


现象原因

Server Actions的本质是客户端向服务端发起的HTTP请求,Next.js等框架为了控制请求负载、保证执行顺序的可预测性,默认会将同一客户端组件发起的多个Server Actions请求串行化处理。

当客户端组件调用Server Actions时,每个printAB()调用都会触发一个独立的服务端请求。框架会让这些请求排队执行:第一个请求执行时,服务端先输出"A",等待1秒后输出"B",请求完成;之后才会处理第二个请求,重复上述流程,最终形成串行的输出结果。

而在纯客户端或纯服务端环境下,函数调用处于同一个事件循环(客户端浏览器或服务端Node.js)中,await只会阻塞当前函数的执行上下文,不会影响其他并发调用的函数,因此两个printAB可以同时启动,先输出两个"A",等待1秒后再输出两个"B"。

规避方法

  • 批量处理请求:将多个需要执行的逻辑合并到一个Server Action中,减少HTTP请求的数量,同时在服务端内部实现并发执行。例如:

    // 服务端定义批量处理的Server Action
    async function printABs(count) {
      const tasks = [];
      for (let i = 0; i < count; i++) {
        tasks.push((async () => {
          console.log("A");
          await new Promise(resolve => setTimeout(resolve, 1000));
          console.log("B");
        })());
      }
      // 并行执行所有任务
      await Promise.all(tasks);
    }
    
    // 客户端组件中调用
    async function f() {
      printABs(2);
    }
    

    这种方式下客户端仅发起一次请求,服务端内部并发处理逻辑,既保证输出符合预期,又能避免多请求串行带来的性能损耗。

  • 优化服务端异步逻辑:如果await的是数据库查询、API调用等IO操作,在单个Server Action中使用Promise.all并行处理这些操作,避免串行等待,提升整体执行效率。

  • 调整框架并发配置:部分框架(如Next.js)提供了取消Server Actions串行限制的选项(如unstable_noStore),但这种方式可能会导致请求过载,需谨慎使用,优先推荐批量处理方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 12:47:51