问题:
在开发视频监控画面相关功能时,发现浏览器总是在一段时间之后崩溃。
通过F12查看网络请求之后发现,监控画面是通过.flv的长连接请求实现,并且在播放器组件销毁之后依旧在后台请求。
因此在多路视频持续播放下,浏览器很快就会因为内存溢出而崩溃(这里使用的是liveplayer播放器,其他播放器暂不知是否有问题)。
官方文档里说置空videoUrl=""可以销毁播放器组件,但是实际并不会中断请求。
由于liveplayer-element.min.js是压缩后的js文件,无法阅读。通过软件格式化后,再由浏览器请求的启动器定位到发起请求的js代码。
self.fetch(o.url, d)
发现使用的是fetch请求,在网上查资料找到一个AbortController对象可以用来手动终止fetch请求(AbortController接口资料)。
由于需要在发起请求的时候带上signal参数,压缩后的js源码也理不清。 所以这里采用了一个取巧的办法:将对象放到window中,在发起请求的地方加一行代码从window中取出对象放到参数中。 但又不能所有请求都用同一个对象,会导致不同业务但同时播放的情况下一起中断,因此需要一个标识来区分。 这里唯一能准确联通的只有一个url,所以实现方式是在url后面追加一个window属性名称字符串来获取正确的对象。
var d = {
method: "GET",
headers: a,
mode: "cors",
cache: "default",
referrerPolicy: "no-referrer-when-downgrade",
//下面是加进去的代码
signal: window[new URL(o.url).searchParams.get("abortControllerName")] && window[new URL(o.url).searchParams.get("abortControllerName")].signal
};
开发流程
- 首先在页面或者vue组件初始化的时候创建一个AbortController对象放到window上。
//不同业务的对象要分开,不然调用方法会一起终止
window["abortControllerObject"] = new AbortController()
//或者绑定到vue组件上,方便使用
window[this.abortControllerName] = new AbortController()
- 在播放前处理一下url,追加一个abortControllerName的参数(这个参数名不可变,写死在了liveplayer-element.min.js的源码中)
let url = new URL(flvUrl)
url.searchParams.append("abortControllerName", this.abortControllerName)
this.$refs.player.setAttribute("video-url", url.href)
- 在变更播放器videoUrl的值或者组件重新渲染前,都需要中断一下请求。 并且需要重新创建一个AbortController对象!!! 因为它里面signal的值是只读的,如果中断一次后继续使用该对象,那么后面的请求是发不出去的!
window[this.abortControllerName].abort()
window[this.abortControllerName] = new AbortController()
- 在组件销毁前中断所有请求
window[this.abortControllerName].abort()
网友评论