vue动态创建iframe导致内存泄漏

问题:vue动态创建iframe导致内存泄漏
描述:点击按钮动态创建Iframe,删除时内存释放不完全,导致内存泄漏
index.vue
<template>
  <div class="container">
    <el-button type="primary"
               @click="handleClick">{{ btnText }}
    el-button>
    <div ref="iframeContainer"
         style="margin-top: 16px;">
    div>
  div>
template>

<script>

export default {
  name: 'index',
  methods: {
    //按钮点击事件
    handleClick() {
      switch (this.btnText) {
        case "创建iframe":
          this.createIframe();
          break;
        case "删除iframe":
          this.deleteIframe();
          break;
      }
    },
    //创建iframe
    createIframe() {
      let iframe = document.createElement('iframe');
      iframe.src = "http://localhost:8082/#/myIframe";
      iframe.width = "400px";
      iframe.height = "800px";
      iframe.id = 'myiframe';
      this.$refs.iframeContainer.appendChild(iframe);
      this.btnText = "删除iframe";
    },
    //删除iframe
    deleteIframe() {
      let iframe = document.getElementById('myiframe');
      iframe.src = "about:blank";
      iframe.contentWindow.document.write("");
      iframe.contentWindow.document.clear();
      iframe.contentWindow.close();
      this.$refs.iframeContainer.removeChild(iframe);
      this.btnText = "创建iframe";
    }
  },
  data() {
    return {
      iframeShow: false,
      btnText: "创建iframe"
    }
  }
}
script>

<style>
.container {
  padding: 16px;
}
style>


img

myIframe.vue
<template>
  <div>
    <el-form ref="form" :rules="formRules" :model="formData" :label-width="labelWidth">
      <el-form-item label="field1" :col="1" prop="field1">
          <el-input v-model="formData.field1" placeholder="field1">el-input>
      el-form-item>
      <el-form-item label="field2" :col="1" prop="field2">
        <el-input v-model="formData.field2" placeholder="field2" :data="regionList">el-input>
      el-form-item>
      <el-form-item label="field4" :col="2">
        <el-input v-model="formData.field4" placeholder="field4">el-input>
      el-form-item>
      <el-form-item label="field5" :col="1" >
        <el-input v-model="formData.field5" placeholder="field5">el-input>
      el-form-item>
      <el-form-item label="field6" :col="1">
        <el-input v-model="formData.field6" placeholder="field6">el-input>
      el-form-item>
      <el-form-item label="field7" :col="1">
        <el-input v-model="formData.field7" placeholder="field7">el-input>
      el-form-item>
      <el-form-item label="field8" :col="1">
        <el-input v-model="formData.field8" placeholder="field8">el-input>
      el-form-item>
      <el-form-item label="field9" :col="1">
        <el-input v-model="formData.field9" placeholder="field9">el-input>
      el-form-item>
      <el-form-item label="field10" :col="1">
        <el-input v-model="formData.field10" placeholder="field10">el-input>
      el-form-item>
      <el-form-item label="field3" :col="2">
        <el-input v-model="formData.field3" placeholder="field3" type="textarea" class="demo-remark">el-input>
      el-form-item>
      <el-form-item :col="1">
        <el-button type="primary" @click="onSubmit">查询el-button>
      el-form-item>
    el-form>
  div>
template>

<script>
export default {
  name: 'iframe',
  mounted() {

  },
  methods: {
    onSubmit() {
      this.$refs.form.validate();
    }
  },
  data() {
    return {
      colsNumInRow:1,
      labelWidth:'80px',
      formData: {
        field1: '',
        field2: '',
        field3: '',
        field4: '',
        field5: '',
        field6: '',
        field7: '',
        field8: '',
        field9: '',
        field10: ''
      },
      regionList: [{"code":"shanghai","name":"上海"}, {"code":"beijing","name":"北京"}],
      formRules: {
        field1: [{required: true, message: '必填项', trigger: 'change'}],
        field2: [{required: true, message: '必填项', trigger: 'change'}]
      },
    }
  }
}
script>

<style scoped>

style>

img

在删除iframe之前,应该先清除iframe内部的内容,确保内存得到释放。在 deleteIframe 方法中添加清除iframe内容的操作。

修改后的代码如下:

deleteIframe() {
  let iframe = document.getElementById('myiframe');
  iframe.src = "about:blank";
  iframe.contentWindow.document.write("");
  iframe.contentWindow.document.clear();
  iframe.contentWindow.close();
  this.$refs.iframeContainer.removeChild(iframe);
  iframe = null; //手动释放iframe对象
  this.btnText = "创建iframe";
}


在删除iframe后,可以手动释放iframe对象,以便帮助JavaScript垃圾回收器回收内存。
注意:应该尽量避免动态创建iframe,因为iframe会阻塞主线程,影响页面的性能和用户体验。如果需要加载外部页面,可以使用 window.open 方法打开新窗口,或者使用Vue的路由功能在同一个页面中切换路由。

用JS处理一下


if (this.sessionId) {
   this.srcUrl = `${this.$route.params.menuRoute}&auth_token=${this.sessionId}`
   let box = document.getElementById('iframe_box')
   let iframe = document.getElementsByTagName('iframe')
   if (iframe.length > 0) {
        box.removeChild(iframe[0])
   }
   const iframeNew = document.createElement('iframe')
   iframeNew.src = this.srcUrl
   iframeNew.frameborder = '0'
   iframeNew.style="width: 100%;height: 87vh !important;border: none;"
   box.appendChild(iframeNew)
}

希望这两篇文章可以帮到你
https://www.jianshu.com/p/259fbb466b67
https://www.jianshu.com/p/bf0df6b8fae9

在 Vue 中创建 iframe 的方式可能导致内存泄漏,这是因为在删除 iframe 时,并不会将 iframe 中创建的全局对象等资源全部释放,导致这些资源一直存在于内存中,从而导致内存泄漏。

要解决这个问题,可以考虑以下几个方案:

将 iframe 中创建的全局对象等资源手动清除:在删除 iframe 前,手动清除 iframe 中创建的全局对象、事件监听器等资源。需要注意的是,有些浏览器不支持 iframe 的垃圾回收,需要等待一段时间才能完全清除。

使用 Vue 的 keep-alive 组件:通过将 iframe 放入 keep-alive 组件中,可以在 iframe 不再需要时将其卸载并释放所有资源。需要注意的是,keep-alive 组件只有在 iframe 被卸载时才会起作用,因此需要确保在不需要 iframe 时及时卸载它。

使用第三方库:有一些第三方库可以帮助解决 iframe 内存泄漏的问题,例如 vue-iframe、vue-iframe-sandbox 等。

根据你给出的代码,做如下改进:
在动态创建和删除 iframe 的过程中,确保在删除时清理 iframe 的内容,以便释放内存。可以使用如下方法修改 deleteIframe 方法:

deleteIframe() {
  let iframe = document.getElementById('myiframe');
  if (iframe) {
    // 将 iframe 的 src 赋为空字符串
    iframe.src = "";
    // 立即释放 iframe 的内存
    iframe.contentWindow.document.write("");
    iframe.contentWindow.close();
    // 将 iframe 从 DOM 中删除
    this.$refs.iframeContainer.removeChild(iframe);
  }
  this.btnText = "创建iframe";
}

此外,还可以在组件销毁时,手动将 iframe 从 DOM 中删除,以确保释放内存。可以在组件的 beforeDestroy 钩子中添加如下代码:

beforeDestroy() {
  let iframe = document.getElementById('myiframe');
  if (iframe) {
    // 将 iframe 的 src 赋为空字符串
    iframe.src = "";
    // 立即释放 iframe 的内存
    iframe.contentWindow.document.write("");
    iframe.contentWindow.close();
    // 将 iframe 从 DOM 中删除
    this.$refs.iframeContainer.removeChild(iframe);
  }
}

在你的vue组件中动态创建iframe,然后删除iframe时内存泄漏的问题,可能是由于以下原因:

1.创建iframe时,没有设置合适的id或者name,导致后面无法正常查找到该iframe元素。

2.删除iframe时,没有对iframe元素进行完全的清理和释放,例如没有释放iframe元素所绑定的事件、没有清空iframe元素的src等。

以下是解决内存泄漏的代码:

<template>
  <div class="container">
    <el-button type="primary" @click="handleClick">{{ btnText }}</el-button>
    <div ref="iframeContainer" style="margin-top: 16px;"></div>
  </div>
</template>

<script>
export default {
  name: 'index',
  methods: {
    handleClick() {
      switch (this.btnText) {
        case "创建iframe":
          this.createIframe();
          break;
        case "删除iframe":
          this.deleteIframe();
          break;
      }
    },
    createIframe() {
      const iframe = document.createElement('iframe');
      iframe.src = "http://localhost:8082/#/myIframe";
      iframe.width = "400px";
      iframe.height = "800px";
      iframe.id = 'myiframe';
      this.$refs.iframeContainer.appendChild(iframe);
      this.btnText = "删除iframe";
    },
    deleteIframe() {
      const iframe = document.getElementById('myiframe');
      if (iframe) {
        iframe.src = "about:blank";
        iframe.contentWindow.document.write('');
        iframe.contentWindow.document.clear();
        iframe.contentWindow.close();
        iframe.removeEventListener('load', this.handleIframeLoad);
        this.$refs.iframeContainer.removeChild(iframe);
      }
      this.btnText = "创建iframe";
    },
    handleIframeLoad() {
      const iframe = document.getElementById('myiframe');
      const iframeWin = iframe.contentWindow;
      iframeWin.addEventListener('unload', this.handleIframeUnload);
      iframeWin.addEventListener('load', this.handleIframeLoad);
    },
    handleIframeUnload() {
      const iframe = document.getElementById('myiframe');
      const iframeWin = iframe.contentWindow;
      iframeWin.removeEventListener('unload', this.handleIframeUnload);
      iframeWin.removeEventListener('load', this.handleIframeLoad);
    },
  },
  data() {
    return {
      iframeShow: false,
      btnText: "创建iframe",
    };
  },
  mounted() {
    window.addEventListener('message', this.handleIframeMessage);
  },
  beforeDestroy() {
    window.removeEventListener('message', this.handleIframeMessage);
  },
};
</script>

<style>
.container {
  padding: 16px;
}
</style>

在上面的代码中,我们添加了一些事件监听器来解决内存泄漏问题:

1.在创建iframe时,我们给iframe绑定了一个load事件处理函数,用于在iframe加载完成时添加其他事件监听器。

2.在删除iframe时,我们首先需要检查该iframe是否存在,然后移除所有与之相关的事件监听器,并使用removeChild()方法将其从DOM中删除。

3.我们还添加了一些其他的事件监听器,如message事件、unload事件等。这些事件监听器的作用是在适当的时候进行一些清理和释放操作,从而确保内存不会

您好,关于您提出的vue动态创建iframe导致内存泄漏的问题,这里推荐如下解决方法:
1、 删除ifram方法示例:

/**
 * 销毁iframe,释放iframe所占用的内存。
 
* @param iframe 须要销毁的iframe对象
*/
function destroyIframe(iframe){
    //把iframe指向空白页面,这样能够释放大部分内存。
    iframe.src = 'about:blank';
    try{
        iframe.contentWindow.document.write('');
        iframe.contentWindow.document.clear();
    }catch(e){}
    //把iframe从页面移除
    iframe.parentNode.removeChild(iframe);
   iframe = null;
}

以上代码中注意加上异常捕获,其次最后要移除iframe节点,最后iframe 对象设置为null

2、代码中避免频繁动态创建iframe,更换其他方式实现相应的功能

以下答案引用自GPT-3大模型,请合理使用:

示例:
解决方案:
1.在删除iframe的时候,要保证onload事件处理函数被卸载,这样才能释放一些在onload函数中定义的对象。
2.在删除iframe的时候,应把iframe的src属性设置为about:blank,这样可以避免IE情况下浏览器不释放内存。
3.在删除iframe的时候,要尽量清空iframe的内容,这样可以释放掉之前iframe中定义的所有变量和对象,否则可能导致内存泄漏。
4.在删除iframe的时候,要尽量关闭这个iframe的window对象,这样可以能释放掉window中动态定义的所有变量和对象,否则可能导致内存泄漏。

以上方案的代码示例如下:
index.vue
<template>
  <div class="container">
    <el-button type="primary"
               @click="handleClick">{{ btnText }}
    </el-button>
    <div ref="iframeContainer"
         style="margin-top: 16px;">
    </div>
  </div>
</template>

<script>

export default {
  name: 'index',
  methods: {
    //按钮点击事件
    handleClick() {
      switch (this.btnText) {
        case "创建iframe":
          this.createIframe();
          break;
        case "删除iframe":
          this.deleteIframe();
          break;
      }
    },
    //创建iframe
    createIframe() {
      let iframe = document.createElement('iframe');
      iframe.src = "http://localhost:8082/#/myIframe";
      iframe.width = "400px";
      iframe.height = "800px";
      iframe.id = 'myiframe';
      this.$refs.iframeContainer.appendChild(iframe);
      this.btnText = "删除iframe";
    },
    //删除iframe
    deleteIframe() {
      let iframe = document.getElementById('myiframe');
      // 清空onload事件处理函数
      iframe.onload = null;
      // 把iframe的src属性设置为about:blank
      iframe.src = "about:blank";
      // 清空iframe的内容
      iframe.contentWindow.document.write("");
      iframe.contentWindow.document.clear();
      // 关闭iframe的Window对象
      iframe.contentWindow.close();
      // 移除iframe
      this.$refs.iframeContainer.removeChild(iframe);
      this.btnText = "创建iframe";
    }
  },
  data() {
    return {
      iframeShow: false,
      btnText: "创建iframe"
    }
  }
}
</script>

<style>
.container {
  padding: 16px;

如果我的回答解决了您的问题,请采纳我的回答

解决方案:

  1. 在删除iframe之前将它的src属性设置成空,这样就可以确保页面不会继续加载,从而避免内存泄漏;
  2. 在删除iframe之前,将iframe的document对象中的所有元素都清空;
  3. 在删除iframe之前,关闭iframe的contentWindow,这样可以确保页面不会继续加载;
  4. 在删除iframe之前,将iframe的引用设置为null,从而释放内存。

检查你src的指向,可能是循环嵌套了

Vue动态创建iframe可能会导致内存泄漏,这是由于Vue在更新DOM时,会将旧的DOM节点从内存中删除,但是由于iframe中的内容不会被Vue更新,所以会导致内存泄漏。为了解决这个问题,可以在每次更新DOM时,将iframe中的内容也更新,以避免内存泄漏。

在你的代码中,删除 iframe 的方法应该遵循以下步骤:

1、将 iframe 的 src 属性设置为 about:blank。
2、将 iframe 的 contentWindow 对象的 document 对象的 write 和 clear 方法执行。
3、执行 contentWindow 对象的 close 方法关闭窗口。
4、从父元素中删除 iframe 元素。
但是在你的代码中,你忽略了第 2 步,即没有清空 contentWindow 对象的 document。这可能会导致内存泄漏。

因此,尝试将 deleteIframe 方法更新为以下内容:

deleteIframe() {
  let iframe = document.getElementById('myiframe');
  iframe.src = "about:blank";
  iframe.contentWindow.document.write("");
  iframe.contentWindow.document.clear();
  iframe.contentWindow.close();
  this.$refs.iframeContainer.removeChild(iframe);
  this.btnText = "创建iframe";
}


在这个版本的方法中,我们增加了第 2 步,清空了 contentWindow 对象的 document。

题主,这个问题我来替你解决,若有帮助,还望采纳,点击回答右侧采纳即可。

解决方案:清空iframe内容,并移除iframe节点。

var el = document.getElementById("IFrame1");
            if (el) {
                iframe = el.contentWindow;
 
                //清除文档
                el.src = 'about:blank';
                try {
                    iframe.document.write('');
                    iframe.document.clear();
 
                    CollectGarbage();
                } catch (e) { };
 
                //清除节点
               var _parentElement = el.parentNode;
                if (_parentElement) {
                    _parentElement.removeChild(el);
 
   }
            }

此方法在重新加载iframe时都会释放一定的内存(可以从进程中看到内存的变化),但加载后新增的内存比释放的内存要多很多,再多次加载后还是会导致内存溢出

还有的说是IE的bug,要用CollectGarbage()函数进行垃圾回收,但经过测试,此函数没有效果,内存溢出也不仅仅在IE存在,火狐和谷歌浏览器都有此现象,只是溢出程度较轻

使用$.get替换iframe动态加载html,同样会导致内存溢出,看来不是iframe的原因

$.get(src, function (data) { //初始將a.html include div#iframe
                    $("#center").empty();
                    $("#center").html(data);
                });

上述方法确实释放了一定的内存,但动态加载新的iframe后溢出了更多的内存,看来不仅仅是这方面的原因。后来经过调试代码,发现iframe页面引入了大量的js库,大概有几十种,如果删除一些内存溢出现象就会得到缓解,看来这就是原因。下一步准备对js库进行压缩和合并,看能否降低内存溢出。

Vue 动态创建iframe时,需要在创建的同时并绑定一个移除事件,用于回收销毁这个iframe,解决方法:

created(){
this.$nextTick(()=>{
var iframe = document.createElement('iframe');
iframe.src = 'https://xxx.xxx.xxx';
document.body.appendChild(iframe);
iframe.addEventListener('onload', ()=>{
// ...
})
iframe.addEventListener('onunload', ()=>{
iframe.remove() // 回收销毁当前创建的iframe
})
})
}