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

React.js中基于BLE的延迟更新:如何仅发送最新请求?

问题:BLE设备的延迟更新(仅发送最新操作)

我正在使用基于浏览器的BLE技术,该技术同一时间仅允许执行一次更新操作。我希望在用户操作后尽快向设备发送更新,但仅发送两次更新调用之间的最后一次更新(即不排队逐个发送)。

举个例子:如果用户快速点击按钮多次,我希望尽快发送更新,但必须等上一次更新完成后才能发下一次,同时不想用“正在发送”的模态框阻止用户操作。

我写了一段示例代码来演示问题(现有代码存在冲突,里面的useEffect是用来确保发送最终状态的临时方案):

import React from "react";
import ReactDOM from "react-dom";
import { useState, useEffect } from "react";

import "./styles.css";

// 模拟BLE调用
window.sending = false;

window.testSend = (n) => {
  if (window.sending) {
    throw new Error("Busy");
  }
  window.sending = true;

  console.log("DataSent: " + n);

  return new Promise((resolve) =>
    setTimeout(() => {
      window.sending = false;
      resolve();
    }, 1000)
  );
};

function App() {
  const [count, setCount] = useState(0);
  const [sendingData, setSendingData] = useState(false);

  // 临时方案
  useEffect(() => {
    const id = setTimeout(() => {
      window.testSend(count).then(() => setSendingData(false));
    }, 2000);

    return () => clearTimeout(id);
  }, [sendingData]);

  function inc() {
    setCount(count + 1);
    sendDataSlowly(count + 1);
  }

  function sendDataSlowly(newData) {
    if (sendingData) {
      return;
    }

    setSendingData(true);

    window.testSend(newData).then(() => setSendingData(false));
  }

  return (
    <div className="App">
      <button onClick={inc}>Click Me {count}</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

有没有实现这类延迟更新的标准模式?我试过在sendDataSlowly里加“LastMissed”状态,但总是没法保证发送正确的最新数据,还容易陷入循环。


标准解决方案:跟踪最新待发送值 + 自动重试机制

核心思路是维护两个状态:

  • sendingData:标记当前是否正在执行BLE发送操作
  • pendingData:保存最新的待发送数据,如果当前正在发送,新的操作只会更新这个值,不会触发重复发送

当当前发送完成后,自动检查是否有未发送的最新数据,如果有就立即发送,这样就能保证只发送每次操作间隙的最后一次更新。

修改后的完整代码如下:

import React from "react";
import ReactDOM from "react-dom";
import { useState, useEffect } from "react";

import "./styles.css";

// 模拟BLE调用
window.sending = false;

window.testSend = (n) => {
  if (window.sending) {
    throw new Error("Busy");
  }
  window.sending = true;

  console.log("DataSent: " + n);

  return new Promise((resolve) =>
    setTimeout(() => {
      window.sending = false;
      resolve();
    }, 1000)
  );
};

function App() {
  const [count, setCount] = useState(0);
  const [sendingData, setSendingData] = useState(false);
  // 新增:保存最新的待发送数据,null表示无待发送
  const [pendingData, setPendingData] = useState(null);

  // 核心逻辑:当不在发送且有待发送数据时,触发发送
  useEffect(() => {
    if (!sendingData && pendingData !== null) {
      setSendingData(true);
      window.testSend(pendingData)
        .then(() => {
          // 发送完成后,清空当前pending数据(因为已经发送了最新的)
          setPendingData(null);
          setSendingData(false);
        })
        .catch((err) => {
          // 发送失败的话,可以根据需求处理,比如重试或者清空pending
          console.error("发送失败:", err);
          setSendingData(false);
        });
    }
  }, [sendingData, pendingData]);

  function inc() {
    const newCount = count + 1;
    setCount(newCount);
    // 只更新最新的待发送数据,不管当前是否在发送
    setPendingData(newCount);
  }

  return (
    <div className="App">
      <button onClick={inc}>Click Me {count}</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

关键流程说明:

  1. 用户点击按钮时,只更新count和pendingData为最新值,不直接触发发送
  2. useEffect会监听sendingData和pendingData的变化:
    • 如果当前没有在发送,且存在待发送数据,就立即启动发送
    • 发送过程中,用户的新操作只会更新pendingData,不会打断当前发送
  3. 发送完成后,清空pendingData并标记发送结束,此时如果有新的pendingData(用户在发送过程中点了多次),useEffect会自动触发下一次发送,且发送的是最新的那个值

这种模式完全避免了手动排队的问题,也不会丢失用户的最新操作,同时不需要阻止用户交互。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 03:26:17