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

React项目socket接收订单消息音频播放延迟,如何实现播放完成后更新Redux

你写的给audio.play()传入回调的写法不可行。

原因说明

HTML 原生的 HTMLAudioElement.play() 方法不支持回调函数作为入参,它的返回值是一个 Promise 实例,仅代表播放操作启动的结果:

  • Promise 状态变为 resolve 代表播放成功启动
  • Promise 状态变为 reject 代表播放失败(比如被浏览器自动播放策略拦截)
    和音频是否播放完成没有任何关联。

你之前遇到的播放延迟问题,核心原因是每次收到订单才创建 Audio 实例触发音频资源加载,酒吧网络环境波动时,资源加载耗时就会导致提示音延迟。

实现方案

核心优化点:提前预加载音频

不要每次收到 socket 消息才初始化音频实例,在项目/组件初始化阶段就提前创建实例、预加载资源,避免每次触发时的加载耗时:

// 组件挂载/项目初始化阶段执行,提前缓存音频实例
const pingAudio = new Audio('/admin/assets/ping.wav');
pingAudio.preload = 'auto'; // 强制预加载完整音频资源

方案1:播放完成后再推送订单(符合你最初的逻辑需求)

注意要兼容播放失败的场景,避免出现提示音故障导致订单漏推的问题:

socket.on('order', (data) => {
  const order = JSON.parse(data);
  // 重置播放进度,避免多次触发时因为上一次播放未完成导致不响
  pingAudio.currentTime = 0;

  pingAudio.play()
    .then(() => {
      // 播放启动成功,监听播放完成事件
      const handlePlayEnd = () => {
        dispatch({ type: 'PUSH_ORDER', payload: { order } });
        // 移除事件监听避免内存泄漏
        pingAudio.removeEventListener('ended', handlePlayEnd);
      };
      pingAudio.addEventListener('ended', handlePlayEnd);
    })
    .catch((err) => {
      // 播放失败时直接推送订单,避免漏单
      console.error('提示音播放失败:', err);
      dispatch({ type: 'PUSH_ORDER', payload: { order } });
    });
});

方案2:订单推送和提示音同时触发(更适配酒吧场景)

如果业务允许订单先展示、提示音同步播放,这种方案逻辑更简单,也完全解决延迟问题:

socket.on('order', (data) => {
  const order = JSON.parse(data);
  // 同时触发订单推送和提示音播放
  dispatch({ type: 'PUSH_ORDER', payload: { order } });
  pingAudio.currentTime = 0;
  pingAudio.play().catch(err => console.error('提示音播放失败:', err));
});

注意事项

浏览器默认禁止没有用户交互的页面自动播放音频,首次打开收银端页面如果没有任何点击操作,第一次提示音可能被拦截。可以在页面加一个「启动接单」按钮,用户点击后再连接socket、或者主动调用一次pingAudio.play().then(() => pingAudio.pause())解锁音频播放权限。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 22:39:04