Howler声音播放卡在队列 state为loading且AudioContext告警如何解决?
问题原因
- 函数组件顶层初始化
Howl实例,每次组件重渲染都会创建新的实例,旧实例未完成资源加载就被丢弃,因此state一直停留在loading状态,触发的播放请求全部堆积在队列中无法执行。 Howl默认会在实例化时自动创建AudioContext,你将实例初始化放在组件渲染阶段,早于用户点击交互,触发Chrome的自动播放策略限制,因此出现AudioContext无法启动的警告。- public目录下的静态资源访问路径需要以
/开头,否则会根据当前页面路由动态拼接路径,大概率出现404,导致音频资源持续加载失败。
修复方案
将Howl实例移到组件外保证仅初始化一次,补充正确的资源路径,第一次用户交互时手动恢复AudioContext即可,修改后代码如下:
import React from "react"; import { Howl, Howler } from "howler"; // 组件外初始化,仅执行一次 const soundEffects = new Howl({ // public目录资源路径加/表示从站点根目录访问 src: ["/effects.webm", "/effects.mp3"], sprite: { loop: [0, 60.013492063492066], deepSounds: [62, 266.4691383219955], screwdriver: [268, 293.9140589569161], }, }); export default function Sounds() { const handleLoopPlay = () => { // 用户交互时恢复AudioContext,消除警告 Howler.resume(); soundEffects.play("loop"); }; return ( <div> <button onClick={handleLoopPlay}>Play loop</button> </div> ); }
如果不想将实例放在组件全局作用域,也可以用useRef包裹保证仅初始化一次:
import React, { useRef } from "react"; import { Howl, Howler } from "howler"; export default function Sounds() { const soundEffectsRef = useRef(new Howl({ src: ["/effects.webm", "/effects.mp3"], sprite: { loop: [0, 60.013492063492066], deepSounds: [62, 266.4691383219955], screwdriver: [268, 293.9140589569161], }, })); const handleLoopPlay = () => { Howler.resume(); soundEffectsRef.current.play("loop"); }; return ( <div> <button onClick={handleLoopPlay}>Play loop</button> </div> ); }
验证步骤
修改后打开浏览器开发者工具的网络面板,刷新页面确认音频资源请求返回200,没有404错误即可正常播放。
内容的提问来源于stack exchange,提问作者crevulus
相关产品推荐
相关产品推荐

