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

Redux中间件dispatch返回无结果Promise的原因及解决方法

问题描述

接手一个使用 vanilla Redux 及中间件的 React 项目,Redux 配置如下:

composeEnhancers(applyMiddleware(...middleware.map(f => f(services))))

其中middleware是包含多个函数的中间件数组,services是注入中间件的外部服务对象(如 api 等)。

项目中的中间件示例:

// ...
const throwErrorFlow = ({ api }) => ({ dispatch, getState }) => next => async (action) => {
  next(action)
  if (action.type === actions.THROW_ERROR) {
    try {
      dispatch(actions.setLoadingSlot({ state: false, context: action.payload.context }))

      const context = getState().ui.context

      const payload = { location: action.payload.location, error: action.payload.error?.stack, context }
      console.log(payload);
      await api.context.throwError(payload)
      dispatch(actions.setErrorModalVisibility({ payload, visibility: true }))
    } catch (error) {
      console.log(error);
    }
  }
}

const middleware = [
  middlwareFunction1,
  middlwareFunction2,
  // ...
  throwErrorFlow
]

export default middleware

我创建了一个返回测试字符串的自定义 action 及对应中间件:
自定义 action 代码:

export const customAction = payload => ({
  type: CUSTOM_ACTION,
  payload: payload,
})

自定义中间件代码:

const customAsyncActionFlow = () => storeAPI => next => action => {
  if (action.type === actions.CUSTOM_ACTION) {
    console.log(action);
    return 'TEST!'
  }
  return next(action);
}

const middleware = [
  middlwareFunction1,
  middlwareFunction2,
  // ...
  throwErrorFlow,
  customAsyncActionFlow 
]

export default middleware

在 UI 中调用时:

console.log(dispatch(customAction('Hello World!')));

action 能正常打印,但 dispatch 返回的是Promise {<fulfilled>: undefined}而非预期的'TEST!'。仅保留自定义中间件时一切正常。

疑问点:

  1. 无结果 Promise 的来源是什么?是否与其他中间件无返回值有关?
  2. 如何在保留所有中间件的情况下让 dispatch 返回预期结果?
  3. 项目中每个需与 api 交互的 action 都对应一个中间件(共 20 个),为何自定义返回值会失效?
  4. 能否让自定义 action 仅触发对应的中间件?
问题分析与解决方案

1. 无结果 Promise 的来源

问题出在项目中存在async 类型的中间件(比如throwErrorFlow):

  • async 函数默认会返回一个 Promise,无论是否显式 return。
  • 这些中间件调用next(action)后,没有返回next(action)的执行结果,函数执行完毕后默认返回undefined,最终导致整个 dispatch 链的返回值变成状态为 fulfilled、值为 undefined 的 Promise。

2. 自定义返回值失效的原因

Redux 中间件是按数组顺序链式执行的:

  • 自定义中间件排在所有中间件的最后,而前面的 async 中间件已经把返回值替换成了自己的 Promise,后续中间件的返回值无法覆盖这个 Promise 的最终结果。
  • 只有中间件链中没有 async 中间件时,自定义返回值才能直接被 dispatch 返回。

3. 保留所有中间件并返回预期结果的方案

有两种可行的解决方式:

方案一:修复所有 async 中间件的返回逻辑

确保每个中间件都返回next(action)的结果,保证返回值在中间件链中正确传递:

// 修改后的 throwErrorFlow 示例
const throwErrorFlow = ({ api }) => ({ dispatch, getState }) => next => async (action) => {
  // 先获取 next(action) 的执行结果
  const result = next(action);
  if (action.type === actions.THROW_ERROR) {
    try {
      // ... 原有业务逻辑不变
      dispatch(actions.setLoadingSlot({ state: false, context: action.payload.context }))
      const context = getState().ui.context
      const payload = { location: action.payload.location, error: action.payload.error?.stack, context }
      console.log(payload);
      await api.context.throwError(payload)
      dispatch(actions.setErrorModalVisibility({ payload, visibility: true }))
    } catch (error) {
      console.log(error);
    }
  }
  // 返回 next 的结果,保证中间件链的返回值传递
  return result;
}

这样,处理非目标 action 时,中间件会将后续中间件的返回值继续传递,最终自定义中间件返回的'TEST!'会被正确传递到 dispatch 的返回值中。

方案二:调整自定义中间件的顺序+处理返回值

把自定义中间件移到所有 async 中间件的前面:

const middleware = [
  customAsyncActionFlow, // 移到最前面
  middlwareFunction1,
  middlwareFunction2,
  // ...
  throwErrorFlow
]

此时 dispatch 返回的会是Promise {<fulfilled>: 'TEST!'}(后续的 async 中间件会把非 Promise 值包装成 Promise),如果需要原始的'TEST!',可以在调用时用await:

const result = await dispatch(customAction('Hello World!'));
console.log(result); // 输出'TEST!'

4. 让自定义 action 仅触发对应中间件的方法

Redux 中间件默认会接收所有 action,要实现仅触发对应中间件,可以在自定义中间件中处理完后不调用next(action),阻断 action 向后传递:

const customAsyncActionFlow = () => storeAPI => next => action => {
  if (action.type === actions.CUSTOM_ACTION) {
    console.log(action);
    return 'TEST!'
  }
  // 非自定义 action 才继续传递给下一个中间件
  return next(action);
}

注意:这种方式会让自定义 action 无法到达 reducer,如果自定义 action 需要触发 reducer 更新状态,还是要调用next(action),同时结合方案一修复其他中间件的返回逻辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 22:50:43