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

跨浏览器准确统计audio标签加载进度,解决加载完成判定异常问题

解决方案:精准跟踪音频加载完成状态

问题根源

不同浏览器对onCanPlay事件的触发逻辑存在差异:Firefox会在音频基本加载完成后触发,但Chrome、Edge、Opera会在音频仅能播放一小段时就提前触发,导致进度跳至100%时,高音等大文件音频还未加载完毕;而onCanPlayThrough依赖浏览器对网络的预估,可靠性极差,无法作为判断标准。


方案1:基于Promise的精确加载跟踪(推荐)

放弃依赖单个事件,改用Promise统一管理所有音频的加载状态,确保所有音频真正加载完成后再结束流程。

步骤1:修改子iframe中的audio标签

移除onCanPlay属性,统一用JS绑定事件:

<audio id='n0' preload='auto'><source src='Sounds/0.mp3' type='audio/mp3'></audio>

步骤2:重构子iframe的JS逻辑

// 存储所有音频加载的Promise实例
const audioLoadPromises = [];
// 获取当前乐器的总音频数量
const totalSamples = parent.window.InstrumentsLastSampleRanks[`<?php echo $_POST['Instrument']; ?>`];

// 页面DOM加载完成后初始化
window.addEventListener('DOMContentLoaded', () => {
  // 遍历所有audio标签
  document.querySelectorAll('audio').forEach(audio => {
    const loadPromise = new Promise((resolve, reject) => {
      // 音频第一帧数据加载完成(已具备完整播放条件)时触发
      audio.addEventListener('loadeddata', () => {
        updateLoadingProgress();
        resolve();
      });
      // 处理音频加载错误,避免卡住流程
      audio.addEventListener('error', (e) => {
        console.error(`音频加载失败:${audio.id}`, e);
        resolve();
      });
      // 主动触发加载
      audio.load();
    });
    audioLoadPromises.push(loadPromise);
  });

  // 所有音频加载完成后执行收尾操作
  Promise.all(audioLoadPromises).then(() => {
    const previewTag = parent.document.getElementById('LoadingPercentageHolder');
    previewTag.innerHTML = '100';
    // 隐藏加载层,显示选项菜单
    Fade(parent.document.getElementById('LoadingDiv'));
    Fade(parent.document.getElementById('OptionsMenu'),'In');
  });
});

// 实时更新加载进度
function updateLoadingProgress() {
  const previewTag = parent.document.getElementById('LoadingPercentageHolder');
  // 统计已完成加载的音频数量
  const loadedCount = audioLoadPromises.filter(p => p.status === 'fulfilled').length;
  const currentlyLoaded = ((loadedCount / totalSamples) * 100).toFixed(3);
  previewTag.innerHTML = currentlyLoaded;
}

核心优势

  • loadeddata事件触发时,音频数据已加载到本地,确保点击即可播放;
  • Promise数组统一管理状态,进度计算精准,不会出现跳变;
  • 兼容所有主流浏览器,避免浏览器事件逻辑差异导致的问题。

方案2:修复自动播放方案的作用域与音量问题

如果坚持使用自动播放的思路,可通过以下方式解决原有问题:

步骤1:修改audio标签

直接用muted属性替代手动设置音量,避免作用域混乱:

<audio id='n0' preload='auto' autoplay muted><source src='Sounds/0.mp3' type='audio/mp3'></audio>

步骤2:调整子iframe的JS逻辑

// 全局状态标记
let isLoaded = false;
let loadedCount = 0;
const totalSamples = parent.window.InstrumentsLastSampleRanks[`<?php echo $_POST['Instrument']; ?>`];

window.addEventListener('DOMContentLoaded', () => {
  document.querySelectorAll('audio').forEach(audio => {
    // 音频播放完毕(确认完全加载)时触发
    audio.addEventListener('ended', () => {
      loadedCount++;
      updateLoadingProgress();
      // 取消静音,恢复正常音量
      audio.muted = false;
      // 所有音频加载完成
      if (loadedCount >= totalSamples) {
        isLoaded = true;
        const previewTag = parent.document.getElementById('LoadingPercentageHolder');
        previewTag.innerHTML = '100';
        Fade(parent.document.getElementById('LoadingDiv'));
        Fade(parent.document.getElementById('OptionsMenu'),'In');
      }
    });
    // 处理播放错误,避免卡住流程
    audio.addEventListener('error', () => {
      loadedCount++;
      updateLoadingProgress();
    });
  });
});

// 更新加载进度
function updateLoadingProgress() {
  const previewTag = parent.document.getElementById('LoadingPercentageHolder');
  const currentlyLoaded = ((loadedCount / totalSamples) * 100).toFixed(3);
  previewTag.innerHTML = currentlyLoaded > 100 ? '100' : currentlyLoaded;
}

// 后续播放音频的方法
function playAudio(audioId) {
  const audio = document.getElementById(audioId);
  if (isLoaded) {
    audio.play();
  }
}

核心修复点

  • 用muted属性替代手动设置音量,彻底解决作用域导致的音量无法恢复问题;
  • 全局变量loadedCount跟踪加载数量,避免作用域混乱;
  • 监听ended事件确认音频已完全加载并播放完毕,确保音频可用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 19:24:55