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

React TypeScript实现DynamoDB轮询异常:仅执行一次且抛TypeError

问题排查与解决方案

问题描述

需要实现React+TypeScript轮询功能:每30秒调用REST API读取DynamoDB记录,直到记录的Status字段变为Success。当前代码仅执行一次查询,且抛出Uncaught (in promise) TypeError: t is not a function错误。

错误原因分析

  1. 轮询函数参数类型不匹配:poll函数要求第一个参数是返回Promise的函数,但你直接执行了callPolling(resJson),把执行后的Promise对象传了进去,而非函数本身。第一次执行await fn()时,相当于尝试调用一个Promise对象,自然触发“不是函数”的错误。
  2. API请求函数语法错误:callPolling内使用了await但未标记为async;同时response变量未声明,会成为全局变量,存在风险。
  3. 未解析API响应:fetch返回的是Response对象,必须调用.json()解析响应体,否则无法获取body.Status字段。

修复后的基础轮询代码

// 封装等待逻辑为Promise
const wait = async function (ms = 1000): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms));
};

// 轮询核心函数:明确类型定义
const poll = async function (
  fn: () => Promise<{ body: { Status: string } }>,
  fnCondition: (result: { body: { Status: string } }) => boolean,
  ms: number
): Promise<{ body: { Status: string } }> {
  let result = await fn();
  // 未满足结束条件时持续轮询
  while (fnCondition(result)) {
    await wait(ms);
    result = await fn();
  }
  return result;
};

// 修正后的API请求函数
async function callPolling(resJson: any): Promise<{ body: { Status: string } }> {
  try {
    const response = await fetch(url, {
      method: 'POST',
      body: JSON.stringify(request_data),
      headers: { 'Content-Type': 'application/json' },
    });
    // 解析响应体为JSON
    return await response.json();
  } catch (e: unknown) {
    console.error('轮询请求失败:', e);
    throw e; // 抛出错误让上层处理,或根据业务返回默认值
  }
}

// 启动轮询:传入函数本身而非执行结果
async function startPolling() {
  try {
    // 条件改为"状态不是Success时继续轮询"
    const validate = (result: { body: { Status: string } }) => result.body.Status !== 'Success';
    const finalResult = await poll(() => callPolling(resJson), validate, 30000);
    console.log('轮询完成,最终结果:', finalResult);
    // 这里处理成功后的逻辑(如更新组件状态)
  } catch (e) {
    console.error('轮询过程出错:', e);
  }
}

// 在React组件中可通过useEffect启动
// useEffect(() => {
//   startPolling();
// }, []);

React环境下的更优实现(避免内存泄漏)

React组件卸载后,未清理的定时器会导致内存泄漏,推荐结合useEffect和useRef管理轮询:

import { useEffect, useRef } from 'react';

const PollingComponent = () => {
  const intervalRef = useRef<NodeJS.Timeout | null>(null);

  // 封装API请求
  const fetchRecord = async (resJson: any) => {
    try {
      const response = await fetch(url, {
        method: 'POST',
        body: JSON.stringify(request_data),
        headers: { 'Content-Type': 'application/json' },
      });
      return await response.json();
    } catch (e) {
      console.error('请求失败:', e);
      throw e;
    }
  };

  // 轮询逻辑
  const startPolling = async () => {
    const checkStatus = async () => {
      try {
        const result = await fetchRecord(resJson);
        if (result.body.Status === 'Success') {
          console.log('轮询完成:', result);
          // 停止轮询
          if (intervalRef.current) {
            clearInterval(intervalRef.current);
            intervalRef.current = null;
          }
          // 执行成功后的业务逻辑(如更新state)
        }
      } catch (e) {
        console.error('轮询检查失败:', e);
        // 可选择是否继续轮询,或终止
      }
    };

    // 先立即执行一次,再启动定时轮询
    await checkStatus();
    intervalRef.current = setInterval(checkStatus, 30000);
  };

  useEffect(() => {
    startPolling();
    // 组件卸载时清理定时器
    return () => {
      if (intervalRef.current) clearInterval(intervalRef.current);
    };
  }, []);

  return <div>轮询中...</div>;
};

export default PollingComponent;

关键注意事项

  • 必须处理请求错误,避免单次失败导致整个轮询终止(可根据业务选择是否继续尝试)。
  • React组件中务必清理定时器,防止内存泄漏。
  • 尽量明确TypeScript类型,减少any的使用,提升代码健壮性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 00:22:12