iframe中WebGLRenderingContext.createShader返回null的调试与解决
WebGL createShader 返回 null 问题排查与解决
问题现象
页面中存在一个加载于iframe内的WebGL画布,当将iframe导航离开WebGL内容后再返回时,WebGLRenderingContext.createShader()调用会返回null,且无任何错误抛出。重新加载iframe内容无法解决该问题,仅刷新整个浏览器窗口才能恢复,但这会丢失父页面的会话配置与数据,因此不可行。
相关编译着色器代码
function CompileShader(gl, type, source) { const shader = gl.createShader(type); if(shader == null){ console.error("gl.createShader returned null!"); } // Send the source to the shader object gl.shaderSource(shader, source); // Compile the shader program gl.compileShader(shader); if (!gl.getShaderParameter(shader, GL.COMPILE_STATUS)) { console.error("Could not compile shader.\n" + gl.getShaderInfoLog(shader)); } return shader; }
排查过程
经排查发现问题核心与画布/上下文管理相关:
- 在iframe父页面内存中创建了画布,但未添加到父页面DOM,直接将其作为WebXR xrSession的上下文,xrSession会在子iframe请求时共享给它,以此在多个页面间复用单个xrSession(每个页面单独创建销毁会话会导致OpenXR不稳定)。
- 若需将XR视图镜像到页面,需将画布通过
appendChild添加到内容页面的DOM,并在unload时removeChild。但第2/3/4次加载内容页面时,shaderSource调用会失败。 - 第一个内容页面卸载后,画布和上下文在父页面内存中仍保持有效,但后续页面加载重复使用着色器时,画布会停止渲染。
解决方案
将内容页面卸载后的画布传回父页面并附加到父页面body上。
原以为只要父页面内存中保持画布引用就能正常工作,但实际发现:当画布所附加的文档销毁且未附加到其他文档时,画布上下文的某些未知内部部分会损坏,仅靠内存引用无法维持上下文正常工作。
内容的提问来源于stack exchange,提问作者Reahreic
相关产品推荐
相关产品推荐

