Repository: nuxt/nuxt
File: packages/nuxt/src/app/composables/asyncData.ts (TypeScript)

Code before:
> (nuxtApp: NuxtApp, key: string, _handler: (ctx?: NuxtApp) => Promise<ResT>, options: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, initialCachedData?: NoInfer<DataT>): CreatedAsyncData<ResT, NuxtErrorDataT, DataT, DefaultT> {
  nuxtApp.payload._errors[key] ??= asyncDataDefaults.errorValue

  const hasCustomGetCachedData = options.getCachedData !== getDefaultCachedData

  // When prerendering, share payload data automatically between requests
  const handler = import.meta.client || !import.meta.prerender || !nuxtApp.ssrContext?._sharedPrerenderCache
    ? _handler
    : () => {
        const value = nuxtApp.ssrContext!._sharedPrerenderCache!.get(key)
        if (value) { return value as Promise<ResT> }

        const promise = Promise.resolve().then(() => nuxtApp.runWithContext(() => _handler(nuxtApp)))

        nuxtApp.ssrContext!._sharedPrerenderCache!.set(key, promise)
        return promise
      }

  const _ref = options.deep ? ref : shallowRef
  const hasCachedData = typeof initialCachedData !== 'undefined'
  const unsubRefreshAsyncData = nuxtApp.hook('app:data:refresh', async (keys) => {
    if (!keys || keys.includes(key)) {
      await asyncData.execute({ cause: 'refresh:hook' })
    }
  })
  const asyncData: CreatedAsyncData<ResT, NuxtErrorDataT, DataT, DefaultT> = {
    data: _ref(hasCachedData ? initialCachedData : options.default!()) as any,
    pending: pendingWhenIdle ? shallowRef(!hasCachedData) : computed(() => asyncData.status.value === 'pending'),
    error: toRef(nuxtApp.payload._errors, key) as any,
    status: shallowRef('idle'),
    execute: (opts = {}) => {
      if (nuxtApp._asyncDataPromises[key]) {
        if ((opts.dedupe ?? options.dedupe) === 'defer') {
        // Avoid fetching same key more than once at a time
          return nuxtApp._asyncDataPromises[key]!
        }
        (nuxtApp._asyncDataPromises[key] as any).cancelled = true
      }
      // Avoid fetching same key that is already fetched
      if (granularCachedData || opts.cause === 'initial' || nuxtApp.isHydrating) {
        const cachedData = opts.cause === 'initial' ? initialCachedData : options.getCachedData!(key, nuxtApp, { cause: opts.cause ?? 'refresh:manual' })
        if (typeof cachedData !== 'undefined') {
          nuxtApp.payload.data[key] = asyncData.data.value = cachedData
          asyncData.error.value = asyncDataDefaults.errorValue
          asyncData.status.value = 'success'
          return Promise.resolve(cachedData)
        }
      }
      if (pendingWhenIdle) {
        asyncData.pending.value = true
      }

Review comment (performance):
Ensure that asyncDataDefaults.value is a robust sentinel value for detecting missing cached data in all scenarios. If the default may change type or structure, consider a more explicit check.
```suggestion
  const hasCachedData = initialCachedData !== MISSING_CACHED_DATA
```

Code after:
function createAsyncData<
  ResT,
  NuxtErrorDataT = unknown,
  DataT = ResT,
  PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
  DefaultT = undefined,
> (nuxtApp: NuxtApp, key: string, _handler: (ctx?: NuxtApp) => Promise<ResT>, options: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, initialCachedData?: NoInfer<DataT>): CreatedAsyncData<ResT, NuxtErrorDataT, DataT, DefaultT> {
  nuxtApp.payload._errors[key] ??= asyncDataDefaults.errorValue

  const hasCustomGetCachedData = options.getCachedData !== getDefaultCachedData

  // When prerendering, share payload data automatically between requests
  const handler = import.meta.client || !import.meta.prerender || !nuxtApp.ssrContext?._sharedPrerenderCache
    ? _handler
    : () => {
        const value = nuxtApp.ssrContext!._sharedPrerenderCache!.get(key)
        if (value) { return value as Promise<ResT> }

        const promise = Promise.resolve().then(() => nuxtApp.runWithContext(() => _handler(nuxtApp)))

        nuxtApp.ssrContext!._sharedPrerenderCache!.set(key, promise)
        return promise
      }

  const _ref = options.deep ? ref : shallowRef
  const hasCachedData = initialCachedData !== asyncDataDefaults.value
  const unsubRefreshAsyncData = nuxtApp.hook('app:data:refresh', async (keys) => {
    if (!keys || keys.includes(key)) {
      await asyncData.execute({ cause: 'refresh:hook' })
    }
  })
  const asyncData: CreatedAsyncData<ResT, NuxtErrorDataT, DataT, DefaultT> = {
    data: _ref(hasCachedData ? initialCachedData : options.default!()) as any,
    pending: pendingWhenIdle ? shallowRef(!hasCachedData) : computed(() => asyncData.status.value === 'pending'),
    error: toRef(nuxtApp.payload._errors, key) as any,
    status: shallowRef('idle'),
    execute: (opts = {}) => {
      if (nuxtApp._asyncDataPromises[key]) {
        if ((opts.dedupe ?? options.dedupe) === 'defer') {
        // Avoid fetching same key more than once at a time
          return nuxtApp._asyncDataPromises[key]!
        }
        (nuxtApp._asyncDataPromises[key] as any).cancelled = true
      }
      // Avoid fetching same key that is already fetched
      if (granularCachedData || opts.cause === 'initial' || nuxtApp.isHydrating) {
        const cachedData = 'cachedData' in opts ? opts.cachedData : options.getCachedData!(key, nuxtApp, { cause: opts.cause ?? 'refresh:manual' })
        if (cachedData !== asyncDataDefaults.value) {
          nuxtApp.payload.data[key] = asyncData.data.value = cachedData as DataT
          asyncData.error.value = asyncDataDefaults.errorValue
          asyncData.status.value = 'success'