• 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 an INDEX_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使用踩坑汇总相关推荐

  1. html5 在线白板,Html5 canvas画图白板踩坑

    最近接手了一个小型的H5,最主要的功能大概就是拍照上传和canvas画板了. 主要是记录一下自己菜到像傻子一样的技术. 1.canvas画板隔空打牛!画布越往上部分错位距离越小,越往下距离越大. 2. ...

  2. python替代hadoop_Python连接Hadoop数据中遇到的各种坑(汇总)

    最近准备使用Python+Hadoop+Pandas进行一些深度的分析与机器学习相关工作.(当然随着学习过程的进展,现在准备使用Python+Spark+Hadoop这样一套体系来搭建后续的工作环境) ...

  3. html嵌入audio格式不支持,html5中audio支持音频格式的解决方法

    HTML5 Audio标签能够支持wav, mp3, ogg, acc, webm等格式,但有个很重要的音乐文件格式midi(扩展名mid)却在各大浏览器中都没有内置的支持.不是所有的浏览器都支持MP ...

  4. java顺丰运费接口_对接顺丰丰桥踩坑汇总(写给自己)

    顺丰丰桥使用流程 登录注册丰桥 https://qiao.sf-express.com/index.html 申请一条龙 开发者信息 按提示搞就行了,然后会有个测试月卡,如果正式环境需要申请正式月卡 ...

  5. ReactNative 在丁香医生项目中引入的踩坑日记

    ReactNative 在丁香医生项目中引入的踩坑日记 this没绑定到函数导致空指针 参考 React-Native 踩坑第二弹-undefined is not a function(evalua ...

  6. html5中audio播放器标签属性整理

    html5中audio播放器标签属性整理 HTML5 元素 audio播放器隐藏 audio标签控制函数功能说明 audio 可脚本控制的特性值 只读属性属性说明 HTML5 元素 元素是一个 HTM ...

  7. 在typora中存储图片踩坑总结(最完整版,包括图片的整体转移)

    在typora中存储图片踩坑总结(最完整版) 1.首先是之前一直以为建立一个文件夹存储图片就可以了,不料这个软件存储图片在绝对位置,所以这样你图片的文件夹移动之后就显示不了,这样就很尴尬!!比如下面这 ...

  8. Vue2.0项目中使用sass(踩坑之路)

    今天用2.0创建项目的时候,使用scss一直不成功,一直报错------ 记录一下,防止下次踩坑 1.安装依赖包 vue的webpack项目中需要安装上node-sass.sass-loader和st ...

  9. vue中使用bootstrap4踩坑之旅

    bootstrapvue官网 bootstrap4中文官网 以下文章记录本人的踩坑过程,最后已亲测有效,但不保证是最简便的方法,最好的建议是去bootstrapvue官网看文档直接尝试. 一.引入jq ...

最新文章

  1. 为什么说Netty是性能之王,因为它用了 Reactor 模型啊
  2. Android项目打包开启proguard的混淆优化带来的问题
  3. 4.Nginx配置进阶(四)
  4. Yii2.0学习资源
  5. cocos2d-xna在使用某些场景转换效果时的问题以及修复
  6. 热榜!基于jsp+mysql的JSP在线水果销售商城系统设计实现【建议收藏】
  7. Ext3.4--布局
  8. 完整的python项目实例-《Python爬虫开发与项目实战》pdf完整版
  9. ajax如何获取复选框中的值_Web自动化测试:页面元素信息(属性)的获取
  10. 【Unity3D】计算二维向量夹角(-180到180)
  11. qq怎样发起临时会话(不加好友)
  12. 盲盒小程序源码下载、附赠完整图片素材源码
  13. 彩蛋-管理员root@‘locahost‘ 密码丢失,处理方案。
  14. c语言win32api勾取,第一次用C语言+win32api写窗体应用程序,晕死了
  15. Pygame制作音乐播放器
  16. js UMD规范——AMD和CommonJS的糅合(一)
  17. 坐标转换(像素转换米)
  18. 许啸宇:从内部研发到开源开发之路|OneFlow U
  19. etcher制作linux启动盘,使用Etcher来创建可启动盘的方法
  20. html中ol和li,HTML ol和li标签

热门文章

  1. 路由算法之LS算法和DV算法全面分析
  2. 项目Beta冲刺Day4
  3. CountDownLatch和cyclicbarrier的使用
  4. [转]深入理解Java 8 Lambda(语言篇——lambda,方法引用,目标类型和默认方法)...
  5. Unity3D 多平台_预编译相关宏定义
  6. ActiveMQ学习(四)——应用程序接口
  7. 走吧---------------北岛
  8. python---之os.path.splitext(“文件路径”)
  9. 数据结构上机实践第九周项目2 - 二叉树遍历的递归算法
  10. 静态成员变量和非静态成员变量