如何正确卸载/销毁VIDEO元素

时间:2010-07-15 18:18:00

标签: javascript jquery dom memory-management html5

我正在开发一个实时媒体浏览/回放应用程序,该应用程序在浏览器中使用<video>个对象进行播放(如果可用)。

我正在使用直接javascript和jQuery,

的混合

我特别关注记忆。应用程序永远不会在窗口中重新加载,并且用户可以观看许多视频,因此随着时间的推移,内存管理成为一个大问题。在今天的测试中,我看到内存配置文件按照每个后续加载流式传输的视频大小跳跃,并且永远不会回落到基线。

我尝试了以下相同的结果:

1 - 清空包含已创建元素的父容器,例如:

$(container_selector).empty();

2 - 暂停并删除与“视频”匹配的子项,然后清空父容器:

$(container_selector).children().filter("video").each(function(){
    this.pause();
    $(this).remove();
});
$(container_selector).empty();

是否还有其他人遇到此问题,是否有更好的方法可以做到这一点?

17 个答案:

答案 0 :(得分:60)

从DOM结构中处理视频非常棘手。它可能会导致浏览器崩溃。这是帮助我完成项目的解决方案。

var videoElement = document.getElementById('id_of_the_video_element_here');
videoElement.pause();
videoElement.removeAttribute('src'); // empty source
videoElement.load();

这将重置所有内容,无声无误!

以下是完整的详情和更好的解释http://www.attuts.com/aw-snap-solution-video-tag-dispose-method/

希望它能解决您的疑问。

答案 1 :(得分:16)

据报道这个“解决方案”有效,大概是因为它会使这些视频容器对象可用于垃圾收集(请参阅下面的说明,讨论为什么delete不应该有所作为)。在任何情况下,您的结果可能会因浏览器而异:

$(container_selector).children().filter("video").each(function(){
    this.pause(); // can't hurt
    delete this; // @sparkey reports that this did the trick (even though it makes no sense!)
    $(this).remove(); // this is probably what actually does the trick
});
$(container_selector).empty();

注意:毫无疑问,delete关键字仅用于从对象中删除属性(正如其他人在评论中指出的那样)。在上面的this行之前和之后将delete this记录到控制台,每次都显示相同的结果。 delete this应该什么都不做,没有任何区别。然而,这个答案仍然得到了涓涓细流的投票,人们已经报告说省略delete this会让它停止工作。也许有些浏览器JS引擎如何实现delete,或者浏览器的delete与jQuery与this之间的异常交互有些奇怪。

所以,请注意,如果这个答案解决了你的问题,如果它确实有效,那么就不清楚为什么会出现这种情况,而且它也可能因为各种原因而停止工作。

答案 2 :(得分:4)

要将视频重置为空白而不将其删除

$("#video-intro").first().attr('src','')

停止视频

答案 3 :(得分:3)

delete(this); 

解决方案。如果它适用于x或y,则是浏览器不当行为。阅读here

  

删除操作符从对象中删除属性。

事实是,当autoplay属性打开时,某些浏览器(例如Firefox)会在内存中缓存视频缓冲区。处理是一种痛苦。

从DOM中删除视频标记或暂停它只会产生不稳定的结果。你必须卸载缓冲区。

var video = document.getElementById('video-id');
video.src = "";

我的实验表明它是这样完成的,但遗憾的是这是spec未完全指定的浏览器实现。在src更改后,您不需要调用load()。更改视频标记的src时,隐式调用其上的load(),这在W3C规范中有说明。

答案 4 :(得分:2)

为了澄清后来尝试此操作的人,解决方法是:(在Safari 5.0中使用h264视频确认,在FF / Opera中未经测试)

$(container_selector).children().filter("video").each(function(){
    this.pause();
    delete(this);
    $(this).remove();
});
$(container_selector).empty();

答案 5 :(得分:1)

我在动态加载某些视频时遇到问题。我的 <video> 元素中有两个来源。一个 mp4 和另一个 webm 作为后备。所以我不得不像这样遍历 <source>

function removeMedia(){
    let videos = document.getElementsByTagName('video');
    for(let vid in videos){
        if(typeof videos[vid] == 'object'){
            let srcs = videos[vid].getElementsByTagName('source');
            videos[vid].pause();
            for(let xsrc in srcs){
                if(srcs[xsrc].src !== undefined){
                    srcs[xsrc].src = '';
                }
            }
            videos[vid].load();
            videos[vid].parentNode.removeChild(videos[vid]);
        }
    }
}

答案 6 :(得分:1)

在AngularJS中对我有用的一种解决方案是使用以下代码: 如果您不想删除源网址,并重置为视频的开头

let videoElement = $document[0].getElementById('video-id');
videoElement.pause();
videoElement.seekable.start(0);
videoElement.load();

如果您想从视频标签中删除源,

let videoElement = $document[0].getElementById('video-id');
videoElement.pause();
videoElement.src="";
videoElement.load();

希望有人觉得它有用。

答案 7 :(得分:1)

答案 8 :(得分:1)

this answer不同,此代码段不执行任何有效的DOM操作(无标记删除),也不会针对error触发<video>事件:

var video = document.getElementById('video');
video.removeAttribute('src');
video.load();

此外,它不会触发loadstart事件。它就像它应该工作 - 没有视频,没有负载启动。

在Chrome 54 / FF 49中检查。

答案 9 :(得分:1)

好的,这是一个肯定有效的简单解决方案:

var bodypage = document.getElementsByTagName('body')[0];
var control_to_remove = document.getElementById('id_of_the_element_here');
bodypage.removeChild(control_to_remove);

答案 10 :(得分:0)

{{1}}

答案 11 :(得分:0)

不太复杂。只需将您的src设置为null。

Eg: document.querySelector('#yourVideo').src = null;

它将删除您的视频src属性。完成。

答案 12 :(得分:0)

我在更复杂的级别上遇到了此问题,我们在页面上加载了约80个视频,并且在IE和Edge中存在内存管理问题。我针对类似的问题发布了我们的解决方案,这个问题专门针对我们的问题:https://stackoverflow.com/a/52119742/1253298

答案 13 :(得分:0)

这就是我解决此问题的方法。 我创建了2个视频元素(video1和video2)。 使用完video1后,获取source(src)属性值,然后从DOM中删除video1。

然后将video2源(src)设置为从video1获得的任何值。

请勿使用video1中的流,因为它已缓存在内存中。

希望这会有所帮助。

答案 14 :(得分:0)

这是关于如何关闭相机的答案 - 不仅仅是暂停。它应该停止流 - 而不是视频元素参考: stream.stop()

答案 15 :(得分:0)

我的代码未使用带有<video>标签的src元素,而是使用多个<source>子级来设置多种格式的视频。

要正确销毁并卸载该视频,我不得不在此页面上使用多个答案的组合,结果是:

var videoElement = $('#my-video')
videoElement[0].pause()  // Pause video
videoElement.empty()     // Remove all <source> children
videoElement.load()      // Load the now sourceless video
delete videoElement      // The call mentioned in other answers
videoElement.remove()    // Removing the video element altogether

希望这对某人有帮助。

答案 16 :(得分:0)

我知道这是一个老问题,但我遇到了同样的问题,并尝试了几乎所有提到 <video>src 属性的解决方案,但所有解决方案似乎都有其缺点。

>

在我指定的情况下,除了 <video> 元素之外,我还同时使用了 <audio> 元素。

当我意识到处理 src 属性可能是错误的做法时,我正在阅读 MDN 上的一篇文章。相反,我重写了所有代码,以将 <source> 元素附加和删除到 <video><audio> 元素。

这是我发现的唯一不会触发新加载或生成错误或其他不良通知的方法。

这是我使用的代码的最小/简化版本(在 Firefox 86 和 Chrome 88 上测试)。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-us">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, minimal-ui, shrink-to-fit=no" />
</head>
<body>
    <button type="button" onclick="play()">Play</button>

    <button type="button" onclick="stop()">Stop</button>

    <video id="myVideo"></video>

    <script type="text/javascript">
        "use strict";

        var myVideo = document.getElementById("myVideo");

        myVideo.onloadstart = () => {
            console.log("onloadstart");
        };

        myVideo.onloadeddata = () => {
            console.log("onloadeddata");
        };

        myVideo.onload = () => {
            console.log("onload");
        };

        myVideo.onerror = () => {
            console.log("onerror");
        };

        function play() {
            while (myVideo.firstChild)
                myVideo.removeChild(myVideo.firstChild);

            var source = document.createElement("source");
            source.src = "example.mp4";
            myVideo.appendChild(source);
            myVideo.load();
            myVideo.play();
        }

        function stop() {
            while (myVideo.firstChild)
                myVideo.removeChild(myVideo.firstChild);

            myVideo.load();
        }
    </script>
</body>
</html>