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

如何取消回调内Pending Promise调用及解决变量更新不生效问题

会议就绪检测中断功能实现方案

问题场景

实现会议就绪检测流程时,需要支持用户随时退出测试的能力:当用户触发退出操作时,立即取消所有处于pending状态的await函数调用。当前核心问题:外部控制变量的值更新后,无法在当前异步代码块内获取到最新值,导致中断逻辑无法正常触发。

原有业务代码

fetch(
  "https://rqyhfmwv4b.execute-api.us-east-1.amazonaws.com/production/join-meeting",
  requestOptions
).then((response) => response.json())
.then(async (data) => {
  // 从服务端Chime API获取响应数据
  const meetingResponse = data.result.meetingResponsee; // CreateMeeting接口返回值
  const attendeeResponse = data.result.attendeeResponsee; // CreateAttendee/BatchCreateAttendee接口返回值
  const configuration = new MeetingSessionConfiguration(
    meetingResponse,
    attendeeResponse
  );
  
  // 初始化会议会话实例
  const meetingSession = new DefaultMeetingSession(
    configuration,
    logger,
    deviceController
  );
  
  const meetingReadinessChecker = new DefaultMeetingReadinessChecker(
    logger,
    meetingSession
  );
  
  // 测试流程逻辑
  if (pauseReadinessTest) {
    setPauseReadinessTest(false);
    return;
  }
  
  if (testParam == "All" && disableStartRedinessTest !== true) {
    await audioTest(deviceController);
    setMeetingTestProgress(15);
    await micTest(meetingSession, meetingReadinessChecker, CheckAudioInputFeedback);
    setMeetingTestProgress(25);
    await videoTest(meetingSession, meetingReadinessChecker, CheckVideoInputFeedback);
    await cameraTest(meetingSession, meetingReadinessChecker, CheckCameraResolutionFeedback);
    setMeetingTestProgress(50);
    await networkTest(meetingReadinessChecker, CheckNetworkTCPConnectivityFeedback, CheckNetworkUDPConnectivityFeedback);
    setMeetingTestProgress(75);
    await streamTest(meetingSession, meetingReadinessChecker, CheckAudioConnectivityFeedback, CheckVideoConnectivityFeedback);
    setMeetingTestProgress(85);
    await screenShareTest(meetingSession, meetingReadinessChecker, CheckContentShareConnectivityFeedback);
    setMeetingTestProgress(100);
    setRefreshIconClass(" ");
    SetDisableStartRedinessTest(false);
    setIsResult("result");
  }
})

根因分析

  • 普通状态变量(比如React useState声明的控制变量)在异步闭包中捕获的是代码执行瞬间的快照值,后续状态更新不会同步到已经启动的异步闭包中,因此判断逻辑永远读不到最新的中断标记。
  • 原生Promise/await没有外部取消机制,只要异步任务进入pending状态,没有专门的中断信号就无法主动终止执行。

修复实现

核心改造点

  • 替换普通状态标记为可实时读取的引用:React场景用useRef存储中断标记,ref的current属性可以在任意时刻读取到最新值,不存在闭包快照问题;原生JS场景直接用普通对象存标记即可。
  • 引入AbortController实现全链路可取消:用AbortController的signal贯穿所有测试方法,触发退出时调用abort方法,所有监听该信号的异步任务会立即终止。

修复后核心代码

// 初始化中断控制器(放在组件/业务模块初始化位置)
const abortController = new AbortController();
const abortSignal = abortController.signal;
const isTestCanceled = { current: false }; // React场景替换为useRef({current: false})

// 用户触发退出测试时调用的方法
const handleCancelTest = () => {
  isTestCanceled.current = true;
  abortController.abort();
  // 可在此处添加测试中断后的UI重置逻辑,比如重置进度、回到初始页
}

fetch(
  "https://rqyhfmwv4b.execute-api.us-east-1.amazonaws.com/production/join-meeting",
  requestOptions
).then((response) => response.json())
.then(async (data) => {
  const meetingResponse = data.result.meetingResponsee;
  const attendeeResponse = data.result.attendeeResponsee;
  const configuration = new MeetingSessionConfiguration(
    meetingResponse,
    attendeeResponse
  );
  
  const meetingSession = new DefaultMeetingSession(
    configuration,
    logger,
    deviceController
  );
  
  const meetingReadinessChecker = new DefaultMeetingReadinessChecker(
    logger,
    meetingSession
  );

  // 监听中断信号,触发时直接清理会话资源
  abortSignal.addEventListener('abort', () => {
    meetingSession?.audioVideo?.stop();
    deviceController?.destroy();
  }, { once: true });
  
  try {
    // 每个步骤执行前先判断中断标记
    if (isTestCanceled.current) return;

    if (testParam == "All") {
      // 所有测试方法都接收abortSignal作为参数,内部监听abort事件主动reject终止
      await audioTest(deviceController, abortSignal);
      if (isTestCanceled.current) return;
      setMeetingTestProgress(15);

      await micTest(meetingSession, meetingReadinessChecker, CheckAudioInputFeedback, abortSignal);
      if (isTestCanceled.current) return;
      setMeetingTestProgress(25);

      await videoTest(meetingSession, meetingReadinessChecker, CheckVideoInputFeedback, abortSignal);
      if (isTestCanceled.current) return;

      await cameraTest(meetingSession, meetingReadinessChecker, CheckCameraResolutionFeedback, abortSignal);
      if (isTestCanceled.current) return;
      setMeetingTestProgress(50);

      await networkTest(meetingReadinessChecker, CheckNetworkTCPConnectivityFeedback, CheckNetworkUDPConnectivityFeedback, abortSignal);
      if (isTestCanceled.current) return;
      setMeetingTestProgress(75);

      await streamTest(meetingSession, meetingReadinessChecker, CheckAudioConnectivityFeedback, CheckVideoConnectivityFeedback, abortSignal);
      if (isTestCanceled.current) return;
      setMeetingTestProgress(85);

      await screenShareTest(meetingSession, meetingReadinessChecker, CheckContentShareConnectivityFeedback, abortSignal);
      if (isTestCanceled.current) return;
      
      setMeetingTestProgress(100);
      setRefreshIconClass(" ");
      SetDisableStartRedinessTest(false);
      setIsResult("result");
    }
  } catch (err) {
    // 捕获abort触发的错误,不需要向上抛出
    if (err.name !== 'AbortError') {
      console.error('测试流程异常', err);
    }
  } finally {
    // 无论中断还是正常完成,都做一次资源清理
    if (isTestCanceled.current) {
      setMeetingTestProgress(0);
      setRefreshIconClass(" ");
    }
  }
})

测试方法改造要求

所有自定义测试方法(audioTest、micTest等)内部需要接收abortSignal参数,在异步逻辑启动前先判断signal.aborted状态,同时添加abort事件监听,触发时直接reject返回AbortError,终止内部异步操作。以audioTest为例:

const audioTest = async (deviceController, signal) => {
  if (signal.aborted) return Promise.reject(new DOMException('测试已取消', 'AbortError'));
  return new Promise((resolve, reject) => {
    const onAbort = () => {
      // 停掉音频采集等内部逻辑
      deviceController.stopAudioInput();
      reject(new DOMException('测试已取消', 'AbortError'));
    };
    signal.addEventListener('abort', onAbort, { once: true });

    // 原有音频测试逻辑
    runAudioTestLogic().then(resolve).catch(reject).finally(() => {
      signal.removeEventListener('abort', onAbort);
    });
  })
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 12:54:18