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

如何在重复触发的事件监听中仅执行一次函数?(语音合成场景)

解决文本转语音(TTS)应用重复朗读的问题

问题根源

你之前的布尔变量executed定义在keyup事件的回调函数内部,每次触发keyup事件都会重新创建这个变量并赋值为false,所以每次判断!executed都是真,导致语音合成被重复调用,布尔值完全起不到控制作用。

解决方案:防抖+朗读状态控制

要实现「输入后延迟0.5-1秒自动朗读,且不重复触发」的需求,需要结合防抖(延迟执行)和朗读状态标记来处理,代码示例如下:

// 在事件外部定义变量,避免每次触发重置
let debounceTimer = null;
let isSpeaking = false;
const speech = new SpeechSynthesisUtterance();

document.querySelector("textarea").addEventListener("keyup", e => {
  // 每次按键时清除之前的定时器,确保只有停止输入后才触发
  if (debounceTimer) {
    clearTimeout(debounceTimer);
  }

  const inputText = e.target.value.trim();
  // 输入为空时,停止当前朗读并返回
  if (!inputText) {
    window.speechSynthesis.cancel();
    isSpeaking = false;
    return;
  }

  // 设置延迟1秒执行朗读(可改为500即0.5秒)
  debounceTimer = setTimeout(() => {
    // 如果当前正在朗读,先终止之前的朗读
    if (isSpeaking) {
      window.speechSynthesis.cancel();
    }

    speech.text = inputText;
    window.speechSynthesis.speak(speech);
    isSpeaking = true;

    // 朗读结束后重置状态标记
    speech.onend = () => {
      isSpeaking = false;
    };
  }, 1000);
});

代码说明

  • 防抖定时器debounceTimer:每次用户按键时,清除上一次的定时器,重新计时。只有当用户停止输入达到设定的延迟时间(1秒/0.5秒),才会执行朗读操作,避免频繁触发。
  • 朗读状态标记isSpeaking:记录当前是否正在朗读,触发新的朗读前先终止之前的朗读,确保始终朗读最新的输入内容,同时在朗读结束后重置标记。
  • 空文本处理:当输入框内容为空时,主动停止朗读,避免无意义的语音输出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 08:56:08