使用CanvasRenderingContext2D时触发SBOX_FATAL_MEMORY_EXCEEDED错误
问题原因
你遇到的内存溢出崩溃完全是循环变量作用域共用导致的死循环问题,和Canvas接口本身没有关系,属于代码编写错误:
- 所有循环的变量
i都没有做块级作用域声明,默认绑定为全局变量,内外层for循环共用同一个全局i,最终触发无限死循环 - 每次进入外层循环体,内层的
for(i = 0; i < 1; i++)都会把i重置为0,导致外层循环的终止条件i < 10永远无法满足 - 死循环过程中会不断调用
moveTo、lineTo、stroke向Canvas上下文追加路径、执行绘制,内存占用持续上涨直到超出浏览器沙箱内存限制,触发SBOX_FATAL_MEMORY_EXCEEDED错误
你认为两段代码逻辑一致是错觉,二者的循环执行逻辑完全不同,你可以运行无Canvas操作的等价代码验证,第二段会直接进入死循环:
// 等价死循环逻辑 for(i = 0; i < 10; i++){ console.log('外层循环执行') for(i = 0; i < 1; i++){ console.log('内层循环执行') } } // 代码永远不会运行到这里
修复方案
只要隔离内外层循环的变量作用域即可:
方案1:给内层循环换个不冲突的变量名
for(i = 0; i < 10; i++){ ctx.moveTo( 200,200 ); // 内层循环换用变量名j for(j = 0; j < 1; j++){ ctx.lineTo(210,210); } ctx.stroke() }
方案2:用let声明块级作用域变量(推荐)
ES6的let声明会绑定到当前块级作用域,内外层的i会成为独立变量,互不干扰:
// 外层用let声明i for(let i = 0; i < 10; i++){ ctx.moveTo( 200,200 ); // 内层也用let声明i,作用域仅在内层循环块 for(let i = 0; i < 1; i++){ ctx.lineTo(210,210); } ctx.stroke() }
内容的提问来源于stack exchange,提问作者Steve Hartley
相关产品推荐
相关产品推荐

