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

Next.js中Server Actions为何串行执行?寻求并行配置方案

Next.js Server Actions 并行调用被排队的问题与解决

问题背景

在Next.js应用中,从客户端组件触发多个Server Actions调用时,发现这些请求会被服务器按顺序排队执行,总耗时为单次请求的N倍(比如5次请求耗时25秒而非5秒),即便客户端用异步Promise方式发起调用。

通过复现代码验证了该现象:

  • 点击"Multiple Server Requests"按钮(同时调用两个Server Actions),服务器日志显示两次请求依次执行,总耗时10秒;
  • 点击"Single Server Requests"按钮(单次请求中在服务器内部并行调用两个函数),则两个函数同时执行,总耗时5秒。

复现代码

serverFunctions.js

"use server"

// 模拟5秒延迟的Server Action
export async function ServerDelay(index) {
    console.log(`calling ${index} ` + new Date().toLocaleTimeString())
    return new Promise(resolve => {
        setTimeout(() => {
            resolve({'index': index, 'time': new Date().toLocaleTimeString()})
        }, 5000)
    })
}

// 服务器内部并行调用的示例
export async function launchOnServer() {
    ServerDelay(1).then(x => {console.log(x)})
    ServerDelay(2).then(x => {console.log(x)})
}

page.js

"use client"

import {ServerDelay, launchOnServer} from "./serverFunctions";

// 客户端本地延迟函数(对比用)
export async function ClientDelay(index) {
  console.log(`calling ${index} ` + new Date().toLocaleTimeString())
  return new Promise(resolve => {
    setTimeout(() => {
      resolve({'index': index, 'time': new Date().toLocaleTimeString()})
    }, 5000)
  })
}

// 客户端同时发起两个Server Actions请求
function launchSeparately() {
  ServerDelay(1).then(x => {console.log(x)})
  ServerDelay(2).then(x => {console.log(x)})
}

// 客户端本地并行调用(对比用)
function clientLaunch() {
  ClientDelay(1).then(x => {console.log(x)})
  ClientDelay(2).then(x => {console.log(x)})
}

// 客户端发起单次请求,服务器内部并行处理
function launchBoth() {
  launchOnServer()
}

export default function Home() {
  return (
    <div>
      <button onClick={launchSeparately}>Multiple Server Requests</button><br/><br/>
      <button onClick={launchBoth}>Single Server Requests</button><br/><br/>
      <button onClick={clientLaunch}>Client Request</button>
    </div>
  )
}

问题原因

Next.js默认对同一客户端会话的Server Actions请求启用会话锁定:当一个请求处理时,会话Cookie会被锁定,后续同会话的请求必须等待前一个请求完成才能执行。这是为了避免并发修改会话数据(如用户会话状态)导致的一致性问题,但同时也限制了无会话依赖的Server Actions的并行执行。

解决方案

方案1:禁用会话锁定(适合无会话依赖的场景)

如果你的Server Action不需要读取或修改会话数据(如不需要访问cookies()、headers()或用户会话),可以在函数中添加unstable_noStore(Next.js 13.4+)来禁用会话锁定,允许并行执行:

"use server"
import { unstable_noStore as noStore } from 'next/cache'

export async function ServerDelay(index) {
  noStore() // 禁用会话锁定,允许并行执行
  console.log(`calling ${index} ` + new Date().toLocaleTimeString())
  return new Promise(resolve => {
    setTimeout(() => {
      resolve({'index': index, 'time': new Date().toLocaleTimeString()})
    }, 5000)
  })
}

修改后,点击"Multiple Server Requests"按钮,服务器日志会显示两个请求同时启动,总耗时约5秒:

calling 1 10:20:00
calling 2 10:20:00
POST / 200 in 5012ms
POST / 200 in 5015ms

方案2:批量请求(推荐,更高效)

将多个请求的参数打包成一个数组,在单个Server Action中内部并行处理所有子请求,这种方式只发起一次网络请求,避免了会话锁定限制,同时减少网络开销:

优化后的serverFunctions.js

"use server"

async function ServerDelay(index) {
    console.log(`calling ${index} ` + new Date().toLocaleTimeString())
    return new Promise(resolve => {
        setTimeout(() => {
            resolve({'index': index, 'time': new Date().toLocaleTimeString()})
        }, 5000)
    })
}

// 批量处理多个请求的Server Action
export async function BatchServerDelays(indices) {
  // 并行执行所有延迟请求
  const results = await Promise.all(indices.map(index => ServerDelay(index)))
  return results
}

客户端调用修改

"use client"
import { BatchServerDelays } from "./serverFunctions";

function launchBatch() {
  // 发起批量请求,传入需要处理的索引数组
  BatchServerDelays([1,2,3,4,5]).then(results => {
    console.log(results)
  })
}

export default function Home() {
  return (
    <div>
      <button onClick={launchBatch}>Batch Server Requests</button><br/><br/>
      {/* 其他按钮... */}
    </div>
  )
}

注意事项

  • 使用unstable_noStore时,必须确保Server Action不依赖会话数据,否则可能导致数据不一致;
  • 批量请求的方式更符合Server Actions的设计初衷,减少客户端与服务器的交互次数,性能更优;
  • 若你的Server Action必须访问会话数据,建议使用批量请求方案,避免会话锁定导致的排队问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 10:10:56