after

after 允许您在响应(或預渲染)完成後安排執行工作。這對於不應阻塞回應的任務和其他副作用(例如日誌記錄和分析)非常有用。

它可以用於伺服器元件 (Server Components)(包括 generateMetadata)、伺服器動作 (Server Actions)路由處理器 (Route Handlers)中介軟體 (Middleware)

此函數接受一個回調函數,該回調將在響應(或預渲染)完成後執行:

import { after } from 'next/server'
// 自訂日誌函數
import { log } from '@/app/utils'

export default function Layout({ children }: { children: React.ReactNode }) {
  after(() => {
    // 在佈局渲染並發送給用戶後執行
    log()
  })
  return <>{children}</>
}
import { after } from 'next/server'
// 自訂日誌函數
import { log } from '@/app/utils'

export default function Layout({ children }) {
  after(() => {
    // 在佈局渲染並發送給用戶後執行
    log()
  })
  return <>{children}</>
}

須知事項: after 不是動態 API (Dynamic API),呼叫它不會導致路由變為動態。如果在靜態頁面中使用,回調將在建置時或在頁面重新驗證時執行。

參考

參數

  • 一個回調函數,將在響應(或預渲染)完成後執行。

持續時間

after 將運行至您路由的預設或配置的最大持續時間。如果您的平台支援,可以使用 maxDuration 路由段配置來設定超時限制。

須知事項

  • 即使響應未成功完成,after 也會執行。包括當拋出錯誤或呼叫 notFoundredirect 時。
  • 您可以使用 React 的 cache 來消除 after 內呼叫的函數重複。
  • after 可以嵌套在其他 after 呼叫中,例如,您可以建立封裝 after 呼叫的實用函數以添加額外功能。

範例

與請求 API 一起使用

您可以在伺服器動作 (Server Actions)路由處理器 (Route Handlers) 中的 after 內使用請求 API,例如 cookiesheaders。這對於在變異後記錄活動非常有用。例如:

import { after } from 'next/server'
import { cookies, headers } from 'next/headers'
import { logUserAction } from '@/app/utils'

export async function POST(request: Request) {
  // 執行變異
  // ...

  // 記錄用戶活動以進行分析
  after(async () => {
    const userAgent = (await headers().get('user-agent')) || 'unknown'
    const sessionCookie =
      (await cookies().get('session-id'))?.value || 'anonymous'

    logUserAction({ sessionCookie, userAgent })
  })

  return new Response(JSON.stringify({ status: 'success' }), {
    status: 200,
    headers: { 'Content-Type': 'application/json' },
  })
}
import { after } from 'next/server'
import { cookies, headers } from 'next/headers'
import { logUserAction } from '@/app/utils'

export async function POST(request) {
  // 執行變異
  // ...

  // 記錄用戶活動以進行分析
  after(async () => {
    const userAgent = (await headers().get('user-agent')) || 'unknown'
    const sessionCookie =
      (await cookies().get('session-id'))?.value || 'anonymous'

    logUserAction({ sessionCookie, userAgent })
  })

  return new Response(JSON.stringify({ status: 'success' }), {
    status: 200,
    headers: { 'Content-Type': 'application/json' },
  })
}

然而,您不能在伺服器元件 (Server Components) 中的 after 內使用這些請求 API。這是因為 Next.js 需要知道樹的哪部分訪問了請求 API 以支援部分預渲染 (Partial Prerendering),但 after 在 React 的渲染生命週期之後運行。

平台支援

了解如何配置 after 當自行託管 Next.js 時。

參考:支援無伺服器平台的 after 在無伺服器環境中使用 after 需要等待異步任務在響應發送後完成。在 Next.js 和 Vercel 中,這是透過名為 waitUntil(promise) 的原語實現的,它延長無伺服器調用的生命週期,直到傳遞給 waitUntil 的所有 Promise 都完成。

如果您希望您的用戶能夠運行 after,您必須提供行為類似的 waitUntil 的實現。

當呼叫 after 時,Next.js 會像這樣訪問 waitUntil

const RequestContext = globalThis[Symbol.for('@next/request-context')]
const contextValue = RequestContext?.get()
const waitUntil = contextValue?.waitUntil

這意味著 globalThis[Symbol.for('@next/request-context')] 預期包含如下對象:

type NextRequestContext = {
  get(): NextRequestContextValue | undefined
}

type NextRequestContextValue = {
  waitUntil?: (promise: Promise<any>) => void
}

以下是實現範例。

import { AsyncLocalStorage } from 'node:async_hooks'

const RequestContextStorage = new AsyncLocalStorage<NextRequestContextValue>()

// 定義並注入 Next.js 將使用的存取器
const RequestContext: NextRequestContext = {
  get() {
    return RequestContextStorage.getStore()
  },
}
globalThis[Symbol.for('@next/request-context')] = RequestContext

const handler = (req, res) => {
  const contextValue = { waitUntil: YOUR_WAITUNTIL }
  // 提供值
  return RequestContextStorage.run(contextValue, () => nextJsHandler(req, res))
}

版本歷史

版本歷史描述
v15.1.0after 成為穩定版。
v15.0.0-rc引入 unstable_after