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

JavaScript中MediaRecorder调用stop后未触发dataavailable事件的问题求助

JavaScript中MediaRecorder调用stop后未触发dataavailable事件的问题求助

我看到你遇到了MediaRecorder的dataavailable事件在调用stop()后没有触发(或触发后数据丢失)的问题,让我帮你分析代码里的问题并给出修复方案。

代码核心问题分析

  1. dataavailable事件内的逻辑颠倒:你在事件回调第一行就执行audioChunks = [],这会导致每次事件触发时先清空数组,再push新数据,完全破坏了音频片段的积累逻辑。
  2. stop按钮的同步清空操作:media_recorder.stop()是异步触发dataavailable事件的,但你在调用stop()后立刻执行audioChunks = [],这会把事件里刚push的音频数据直接清空,让你误以为事件没触发。
  3. 日志输出可读性差:你的demo.innerHTML拼接没有换行,所有内容挤在一起,很难直观跟踪代码执行流程。

修复后的完整代码

var demo = document.getElementById("demo")
const startButton = document.getElementById('start');
const stopButton = document.getElementById('stop');

let media_recorder
let audioChunks = []

navigator.mediaDevices.getUserMedia({ audio: true })
    .then(stream => {
        demo.innerHTML += "已获取麦克风权限<br>";
        media_recorder = new MediaRecorder(stream);
        
        // 修正dataavailable事件逻辑:只积累音频数据,不在此清空数组
        media_recorder.addEventListener('dataavailable', e => {
            audioChunks.push(e.data);
            demo.innerHTML += "dataavailable事件已触发,已收集音频片段<br>";
            
            // 当MediaRecorder状态变为inactive时,说明录制完全停止,可处理音频
            if (media_recorder.state === 'inactive') {
                const audioBlob = new Blob(audioChunks, { type: 'audio/webm' });
                const audioUrl = URL.createObjectURL(audioBlob);
                // 这里可添加播放、上传等业务逻辑
                const audioPlayer = new Audio(audioUrl);
                audioPlayer.play();
                demo.innerHTML += "录制完成!正在播放音频...<br>";
                
                // 播放结束后释放URL,避免内存泄漏
                audioPlayer.onended = () => {
                    URL.revokeObjectURL(audioUrl);
                    demo.innerHTML += "音频播放完毕,已释放资源<br>";
                };
            }
        });

        startButton.addEventListener('click', () => {
            audioChunks = []; // 开始新录制前清空数组
            media_recorder.start();
            demo.innerHTML += 'Recording started! Speak now.<br>';
        });

        stopButton.onclick = () => {
            media_recorder.stop();
            demo.innerHTML += "已发送停止录制请求<br>";
            demo.innerHTML += "Recording stopped!<br>";
            // 移除此处的audioChunks = [],避免清空异步收集的音频数据
        };
    }).catch (err => {
        demo.innerHTML += `获取麦克风权限失败:${err.message}<br>`;
    })

关键修复点说明

  1. 调整dataavailable事件逻辑:移除事件内的数组清空操作,只负责积累音频片段;通过media_recorder.state === 'inactive'判断录制完全结束,此时再执行音频播放、上传等后续逻辑。
  2. 数组清空时机迁移:将audioChunks = []移到start按钮的点击事件中,确保每次新录制都从空数组开始积累数据。
  3. 移除stop事件内的数组清空:stop()触发的dataavailable是异步事件,同步清空会直接丢失刚收集到的音频数据,这是你误以为事件没触发的核心原因。
  4. 优化日志可读性:添加<br>标签让日志内容换行,方便你清晰跟踪代码执行和事件触发流程。

现在你可以测试修复后的代码,点击开始录制后说话,再点击停止,就能看到dataavailable事件触发的日志,并且正常播放录制的音频了。

备注:内容来源于stack exchange,提问作者marco

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 10:44:28