在vue中使用three.js切换页面后销毁,防止内存溢出

产生问题

用three.js写了一个webgl页面,发现这个webgl页面在和普通页面来回切换多次后会导致页面卡顿。

问题原因

重审代码后发现一些问题:

1、three.js在使用过程中产生了大量对象,销毁页面时没有能及时的清除,来回切换页面后这些无用对象会成倍增长。

2、发现页面销毁后,使用requestAnimationFrame去更新动画的方法并没有及时停止执行

3、部分监听器并未及时销毁,如键盘按键的监听,在其他页面依然生效

JavaScript垃圾回收机制

JavaScript 的垃圾回收机制是由 JavaScript 引擎自动执行的,开发者无需手动管理内存,可能采用不同的垃圾回收算法和策略,以最大程度地提高性能和资源利用。在编写 JavaScript 代码时,我们可以通过主动解除对象引用(赋值为 null),帮助垃圾回收器更早地识别和回收不再使用的对象,从而优化内存管理和性能。但在大多数情况下,JavaScript 引擎会根据需要自动进行垃圾回收,确保内存的有效使用和自动清理不再使用的对象。

解决方法

清除three.js产生的对象,removeEventListeners,对渲染器renderer判空停止正在递归的动画函数,代码如下

destroyThreejs() {
      try {
        this.renderer.dispose();
        this.renderer.forceContextLoss();
        this.renderer.content = null;
        let gl = this.renderer.domElement.getContext("webgl");
        if (gl && gl.getExtension("WEBGL_lose_context")) {
          gl.getExtension("WEBGL_lose_context").loseContext();
        }
        this.renderer = null;
        this.camera = null;
        this.scene.traverse((child) => {
          if (child.material) {
            child.material.dispose();
          }
          if (child.geometry) {
            child.geometry.dispose();
          }
          child = null;
        });
        this.scene = null;
      } catch (e) {
        console.error("Failed to destroy threejs", e);
      }
    },
    animate() {
      if (!this.renderer) {
        return;
      }
      requestAnimationFrame(this.animate);
      this.controls.update(); // 更新控制器状态
      TWEEN.update();
      this.renderer.render(this.scene, this.camera);
    },
    removeEventListeners() {
      const dom = this.$refs.three_container;
      window.removeEventListener("keydown", this.toggleFullscreen, false);
      dom.removeEventListener("mousedown", this.onMouseDown, false);
      dom.removeEventListener("wheel", this.onMouseWheel, false);
    },

在beforeDestroy中执行

 beforeDestroy() {
    console.log("销毁");
    this.removeEventListeners();
    this.destroyThreejs();
  },

你可能感兴趣的:(vue,vue,与,three,javascript,vue.js,前端)