When to dispose: How to completely clean up a Three.js scene

tried your code to clear a scene.
It does work but had to remove this line as it throws an error:

this.renderer.forceContextLoss()

error:

Unhandled Promise rejection: Failed to execute ‘shaderSource’ on ‘WebGL2RenderingContext’: parameter 1 is not of type ‘WebGLShader’.

When I remove that line, the scene is cleared.
The scene only contains points and lines, not sure if that is of interest.

Is there nowadays a built-in fn that clears a scene or canvas (to ensure this is properly done)?
Seems like a basic functionality that should be in this lib.
Would simply removing the <canvas> element and unsetting all Three.js vars (renderer, scene, camera, controls) achieve the same thing or would that keep references in GPU memory?
Trying to understand the current recommended way to start over on a clean canvas.

Three.js 0.167.1
Chrome 100.0.4896.160
Win 10 x64

For those who might be interested, here is the example cleanup code that removes GLTF model (gltf_obj) from the scene and also tries to clear GPU.

It is a slightly modified / simplified version of the function from my GLTF Viewer which can be modified and/or simplified further but should cover the general idea of cleaning and disposing, depending of whether only a model is being removed from the scene or cleaning the whole scene (in which case try traversing the scene instead).

      async function scene_cleanup() {
        let texture_maps = [ 'map', 'aoMap', 'alphaMap', 'bumpMap', 'displacementMap', 'envMap', 'lightMap', 'emissiveMap', 'normalMap',
          'metalnessMap', 'roughnessMap', 'anisotropyMap', 'clearcoatMap', 'clearcoatNormalMap', 'clearcoatRoughnessMap',
          'iridescenceMap', 'iridescenceThicknessMap', 'sheenColorMap', 'sheenRoughnessMap', 'specularMap',
          'specularColorMap', 'specularIntensityMap', 'thicknessMap', 'transmissionMap'
        ];

        // Remove GLTF model from the scene
        scene.remove( gltf_obj );

        renderer.clear();

        // If animation_mixer was declared and created uncomment the following lines
        //if (animation_mixer) {
        //  animation_mixer.stopAllAction();

        //  for ( let i = 0; i < animations.length; i++ ) {
        //    animation_mixer.uncacheAction( animations[ i ] );
        //    animation_mixer.uncacheClip( animations[ i ] );
        //  }

        //  animation_mixer.uncacheRoot( animation_mixer.getRoot() );
        //}

        if (gltf_obj.skeleton && gltf_obj.skeleton.boneTexture)
          gltf_obj.skeleton.boneTexture.dispose();

        gltf_obj.traverse( function( child ) {
          if (child.isMesh || child.isPoints || child.isLine)) {
            if (child.skeleton && child.skeleton.boneTexture)
                child.skeleton.boneTexture.dispose();

            if (child.material) {
              if (Array.isArray( child.material )) {
                child.material.forEach( mtl => {
                  if (mtl.uniforms) {
                    Object.keys( mtl.uniforms ).forEach( ( key ) => {
                      if (mtl.uniforms[ key ].value) {
                        let kv = mtl.uniforms[ key ].value;

                        if (Array.isArray( kv ) && kv.length > 0) {
                          kv.forEach( val => {
                            if (val.type && val.type === 1009) val.dispose();
                          });
                        } else {
                          if (kv.type && kv.type === 1009) kv.dispose();
                        }
                      }
                    });
                  } else {
                    for (const prop in mtl) {
                      texture_maps.forEach( tex_map => {
                        if (prop === tex_map) {
                          if (mtl[ prop ]) mtl[ prop ].dispose();
                        }
                      });
                    };
                  }

                  mtl.dispose();
                });
              } else {
                if (child.material.uniforms) {
                  Object.keys( child.material.uniforms ).forEach( ( key ) => {
                    if (child.material.uniforms[ key ].value) {
                      let kv = child.material.uniforms[ key ].value;

                      if (Array.isArray( kv ) && kv.length > 0) {
                        kv.forEach( val => {
                          if (val.type && val.type === 1009) val.dispose();
                        });
                      } else {
                        if (kv.type && kv.type === 1009) kv.dispose();
                      }
                    }
                  });
                } else {
                  for (const prop in child.material) {
                    texture_maps.forEach( tex_map => {
                      if (prop === tex_map) {
                        if (child.material[ prop ]) child.material[ prop ].dispose();
                      }
                    });
                  };
                }

                child.material.dispose();
              }
            }

            child.geometry.dispose();
          }
        });

        // If cleaning the whole scene uncomment the following lines
        //renderer.dispose();

        //while (scene.children.length > 0) {
        //  scene.remove( scene.children[ 0 ] );
        //}
      }

This code will not be cleaning geometries / textures related to environment (they seem to be somehow cached for subsequent use).

If using a console then consider logging the renderer info so you can see how many geometries / textures are being used:

        console.log( 'Memory: ', renderer.info.memory );
        console.log( 'Render: ', renderer.info.render );