React项目中拉取音频文件时如何实现边加载边流式播放?
结论
仅在客户端侧就可以实现音频边拉取边播放的效果,不需要引入socket.io-stream这类额外的依赖,你原有实现的问题在于主动废弃了浏览器原生提供的音频流式播放能力。
问题根源
你原有代码的逻辑是用axios全量拉取完整音频文件后,才生成blob地址投喂给Audio元素,所以必须等文件完全下载完成才能触发播放。而浏览器原生的Audio元素本身就内置了流式加载逻辑:接收到音频资源地址后会自动按需加载缓冲数据,只要拿到足够播放的分片数据就会立刻开始播放,不需要等待全量文件下载完成,完全满足你要的边下边播需求。
优化实现代码
由于你提到实际场景中接口仅返回音频文件的访问路径,代码可以直接简化为如下写法:
const playAudio = async (id) => { try { // 调用接口获取音频文件的真实访问路径 const res = await axiosClient.get(`my.api.com/musics/${id}`) const audioResourceUrl = res.data const audio = new Audio(audioResourceUrl) // 配置预加载策略,auto为自动缓冲足够播放的数据 audio.preload = 'auto' // 也可以监听canplay事件触发后再播放,避免资源不足时报错 // audio.addEventListener('canplay', () => audio.play()) await audio.play() } catch (e) { console.log('play audio error: ', e) } }
进阶优化(可选,接近YouTube Music体验)
如果需要更精细化的播放控制,可以做以下客户端侧优化:
- 提前预加载下一首待播放音频的前几十KB数据,实现切歌秒开效果
- 监听Audio元素的
waiting事件,缓冲不足时展示加载提示,提升用户感知 - 有DRM加密、多码率切换需求的场景,可以使用MediaSource Extensions API自行控制音频分片的拉取和投喂逻辑,普通点播场景不需要用到
关于socket.io-stream方案的说明
该方案更适合实时音频流(比如语音直播、实时通话)场景,你的需求是点播已存储的MP3文件,使用该方案属于过度设计,会额外增加服务端和客户端的维护成本,完全没有必要。
内容的提问来源于stack exchange,提问作者Parham Moieni
相关产品推荐
相关产品推荐

