HTML5中Audio使用踩坑汇总
Cannot read property 'catch' of undefined
原因:在调用play()时,现代浏览器返回的是一个promise,对于执行失败的,会触发一个Unhandled Promise Rejection,但是对于低版本的浏览器,调用play()并不会返回一个promise。
解决:应该在调用play()时做如下处理,增加对playPromise的判断
var playPromise = document.querySelector('video').play();// In browsers that don’t yet support this functionality, // playPromise won’t be defined. if (playPromise !== undefined) {playPromise.then(function() {// Automatic playback started!}).catch(function(error) {// Automatic playback failed.// Show a UI element to let the user manually start playback.}); } 复制代码
参考资料:HTMLMediaElement.play() Returns a Promise
InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable
原因:对于还没有设置src的audio,就直接设置currentTime是会触发一个INVALID_STATE_ERR异常的。即使是设置currentTime = 0也会触发这个异常
解决:在设置currentTime之前,必须先设置audio的src
参考资料:Offsets into the media resource
media .
currentTime
[ = value ]Returns the current playback position, in seconds.
Can be set, to seek to the given time.
Will throw an
INVALID_STATE_ERR
exception if there is no selected media resource. Will throw anINDEX_SIZE_ERR
exception if the given time is not within the ranges to which the user agent can seek.NotAllowedError
原因:在调用play()时可能会触发一个NotAllowedError的reject,原因是因为浏览器在某些情况下播放失败,常见场景是,未通过点击的情况下调用play() ,或者点击事件的回调中是在下一个tick里调用的play,例如在setTimeout里调用的play,再或者新创建了很多个audio元素,但是并不是每个audio都是通过用户点击来调用的play()等等。
场景一:未通过点击等事件绑定,直接调用play(),触发NotAllowedError。解决方法,把调用play()的部分放在事件回调里,如下代码:
playButton.addEventListener("click", () => {audioElem.play() }, false); 复制代码
场景二:在点击事件回调中的下一个tick里调用play(),这种情况的示例代码如下,
// 错误代码示例 playButton.addEventListener("click", () => {setTimeout(() => {audioElem.play()}, 100) }, false); 复制代码
这种情况,某些版本【在iOS12.0.1亲测有坑】也会触发NotAllowedError异常,应该避免这种情况,可以考虑如下hack手段解决
// hack playButton.addEventListener("click", () => {audioElem.muted = truelet p = audioElem.play()if (p !== undefined) {p.then(() => {audioElem.muted = falseaudioElem.pause()setTimeout(() => {audioElem.play()}, 100)}).catch((e) => {console.log(e)})} }, false); 复制代码
场景三:创建了多个audio元素,但是并不是每个audio都是通过用户点击来调用的play()的,这时候某些版本【在iOS12.0.1亲测有坑】也会触发NotAllowedError异常。对于这种情况,最好的办法就是只创建一个audio元素,后面通过改变src来播放不同的音乐资源。只要audio通过了事件回调里调用过play,后续都可以直接调用play了,而无需再次绑定事件回调里去执行,并且这样也可以避免创建多个audio来减少内存使用。
playButton.addEventListener("click", () => {audioElem.src = "https://a.mp3"audioElem.play() }, false);// 后面其他地方,可以改变src来直接play audioElem.src = "https://b.mp3" audioElem.play() 复制代码
iOS 中页面隐藏和显示时,播放audio行为异常
原因:在某些iOS版本中【iOS12.0.1亲测有坑】,当我们监听页面隐藏和显示事件,在隐藏时调用pause() 暂停,显示时调用play()恢复播放。当按下home键,页面进入系统后台时,pause()正常调用,audio被正常暂停,但是但再次进入页面,显示事件中调用play()就会出现异常了,
第一种异常,如果,我们只是单纯的调用
audioElem.play()
,不会抛出任何错误,但是audio实际却没有真正播放,无任何声音;第二种异常,如果我们每次在显示事件中执行如下代码中任意一种场景,都会在很多情况下会抛出一个AbortError异常,极少数情况才会正常播放。
//监听页面显示隐藏事件 addPageVisibilityListener(() => {// 隐藏时暂停audioElem.pause() },() => {// 显示时恢复播放// 重新直接赋值srcaudioElem.src = "https://b.mp3"audioElem.play()// 或者load// audioElem.load()// audioElem.play() }) 复制代码
解决:这两种异常行为应该都是iOS 12.0.1系统本身的bug。我们可以通过如下2中方式来避免这种两种异常的发生,
- 方式1, 显示load(),并监听canplaythrough,推荐使用这种方式
const playAudio = () => {audioElem1.removeEventListener('canplaythrough', playAudio)let p = audioElem.play()if (p !== undefined) {p.catch((e) => {console.log(e)})} } //监听页面显示隐藏事件 addPageVisibilityListener(() => {// 隐藏时暂停audioElem.pause() },() => {// 显示时恢复播放audioElem.load()audioElem.addEventListener('canplaythrough', playAudio) }) 复制代码
- 方式2,通过setTimeout以及retry来hack避免这种异常发生
let playAudio = (retry: boolean) => {let p = audioElem.play();if (p !== undefined) {p.catch((e) => {if (retry) {setTimeout(() => {playAudio(false);}, 0);}});} } //监听页面显示隐藏事件 addPageVisibilityListener(() => {// 隐藏时暂停audioElem.pause() },() => {// 显示时恢复播放setTimeout(() => {playAudio(true)}, 500) }) 复制代码
HTML5中Audio使用踩坑汇总相关推荐
- html5 在线白板,Html5 canvas画图白板踩坑
最近接手了一个小型的H5,最主要的功能大概就是拍照上传和canvas画板了. 主要是记录一下自己菜到像傻子一样的技术. 1.canvas画板隔空打牛!画布越往上部分错位距离越小,越往下距离越大. 2. ...
- python替代hadoop_Python连接Hadoop数据中遇到的各种坑(汇总)
最近准备使用Python+Hadoop+Pandas进行一些深度的分析与机器学习相关工作.(当然随着学习过程的进展,现在准备使用Python+Spark+Hadoop这样一套体系来搭建后续的工作环境) ...
- html嵌入audio格式不支持,html5中audio支持音频格式的解决方法
HTML5 Audio标签能够支持wav, mp3, ogg, acc, webm等格式,但有个很重要的音乐文件格式midi(扩展名mid)却在各大浏览器中都没有内置的支持.不是所有的浏览器都支持MP ...
- java顺丰运费接口_对接顺丰丰桥踩坑汇总(写给自己)
顺丰丰桥使用流程 登录注册丰桥 https://qiao.sf-express.com/index.html 申请一条龙 开发者信息 按提示搞就行了,然后会有个测试月卡,如果正式环境需要申请正式月卡 ...
- ReactNative 在丁香医生项目中引入的踩坑日记
ReactNative 在丁香医生项目中引入的踩坑日记 this没绑定到函数导致空指针 参考 React-Native 踩坑第二弹-undefined is not a function(evalua ...
- html5中audio播放器标签属性整理
html5中audio播放器标签属性整理 HTML5 元素 audio播放器隐藏 audio标签控制函数功能说明 audio 可脚本控制的特性值 只读属性属性说明 HTML5 元素 元素是一个 HTM ...
- 在typora中存储图片踩坑总结(最完整版,包括图片的整体转移)
在typora中存储图片踩坑总结(最完整版) 1.首先是之前一直以为建立一个文件夹存储图片就可以了,不料这个软件存储图片在绝对位置,所以这样你图片的文件夹移动之后就显示不了,这样就很尴尬!!比如下面这 ...
- Vue2.0项目中使用sass(踩坑之路)
今天用2.0创建项目的时候,使用scss一直不成功,一直报错------ 记录一下,防止下次踩坑 1.安装依赖包 vue的webpack项目中需要安装上node-sass.sass-loader和st ...
- vue中使用bootstrap4踩坑之旅
bootstrapvue官网 bootstrap4中文官网 以下文章记录本人的踩坑过程,最后已亲测有效,但不保证是最简便的方法,最好的建议是去bootstrapvue官网看文档直接尝试. 一.引入jq ...
最新文章
- 为什么说Netty是性能之王,因为它用了 Reactor 模型啊
- Android项目打包开启proguard的混淆优化带来的问题
- 4.Nginx配置进阶(四)
- Yii2.0学习资源
- cocos2d-xna在使用某些场景转换效果时的问题以及修复
- 热榜!基于jsp+mysql的JSP在线水果销售商城系统设计实现【建议收藏】
- Ext3.4--布局
- 完整的python项目实例-《Python爬虫开发与项目实战》pdf完整版
- ajax如何获取复选框中的值_Web自动化测试:页面元素信息(属性)的获取
- 【Unity3D】计算二维向量夹角(-180到180)
- qq怎样发起临时会话(不加好友)
- 盲盒小程序源码下载、附赠完整图片素材源码
- 彩蛋-管理员root@‘locahost‘ 密码丢失,处理方案。
- c语言win32api勾取,第一次用C语言+win32api写窗体应用程序,晕死了
- Pygame制作音乐播放器
- js UMD规范——AMD和CommonJS的糅合(一)
- 坐标转换(像素转换米)
- 许啸宇:从内部研发到开源开发之路|OneFlow U
- etcher制作linux启动盘,使用Etcher来创建可启动盘的方法
- html中ol和li,HTML ol和li标签
热门文章
- 路由算法之LS算法和DV算法全面分析
- 项目Beta冲刺Day4
- CountDownLatch和cyclicbarrier的使用
- [转]深入理解Java 8 Lambda(语言篇——lambda,方法引用,目标类型和默认方法)...
- Unity3D 多平台_预编译相关宏定义
- ActiveMQ学习(四)——应用程序接口
- 走吧---------------北岛
- python---之os.path.splitext(“文件路径”)
- 数据结构上机实践第九周项目2 - 二叉树遍历的递归算法
- 静态成员变量和非静态成员变量