在p5.js的draw()中递归调用draw()提速是否安全?求替代方案
关于10 PRINT克隆项目递归调用draw()的安全性与提速方案
首先得给你点个赞——能从Daniel Shiffman的10 PRINT挑战中获得灵感并动手实现,这本身就很棒!不过你提到的在draw()里递归调用自己的方式,确实存在不小的安全问题,咱们先把这个问题说清楚,再给你几个靠谱的提速方案。
为什么递归调用draw()不安全?
JavaScript的函数调用栈是有固定上限的(不同浏览器/环境略有差异,一般在几千到几万层级)。你现在的逻辑是有80%的概率会在当前draw()执行过程中再调用一次draw(),这会不断把新的draw()调用压入调用栈。如果连续触发几次这个80%的概率,调用栈很快就会被撑爆,直接抛出RangeError: Maximum call stack size exceeded的错误,导致程序崩溃。这种方式完全不可控,绝对不建议用。
靠谱的提速方案
方案1:批量绘制(最易实现,保留动画感)
与其每次只画一个格子,不如在单次draw()调用里一次性画多组格子(比如一次画10个、20个),这样能大幅减少draw()的执行次数,同时避免递归的栈溢出风险。修改后的代码大概是这样:
var x = 0, y = 0; var space = 10; var batchSize = 20; // 每次批量绘制的格子数 function setup() { createCanvas(window.innerWidth, window.innerHeight); background(0); strokeWeight(2); } function draw() { stroke(255); // 批量绘制指定数量的格子 for(let i = 0; i < batchSize; i++){ if(random() > 0.5) { stroke('#F26C4D'); line(x, y, x + space, y + space); } else { stroke(255); line(x, y + space, x + space, y); } x += space; if(x >= width) { x = 0; y += space; } // 画满整个画布后停止绘制 if(y >= height){ noLoop(); break; } } }
方案2:一次性绘制所有格子(最快,无动画)
如果不需要逐步绘制的动画效果,直接在setup()里用嵌套循环一次性画完整个画布,这是效率最高的方式,完全不需要依赖draw()循环:
var space = 10; function setup() { createCanvas(window.innerWidth, window.innerHeight); background(0); strokeWeight(2); // 嵌套循环遍历所有格子 for(let y = 0; y < height; y += space){ for(let x = 0; x < width; x += space){ if(random() > 0.5) { stroke('#F26C4D'); line(x, y, x + space, y + space); } else { stroke(255); line(x, y + space, x + space, y); } } } noLoop(); // 不需要再执行draw() } function draw() { // 这里可以留空,因为已经在setup里画完了 }
方案3:用requestAnimationFrame手动控制绘制节奏(更灵活)
如果想要自定义绘制的速度和节奏,可以放弃p5.js的draw()循环,改用原生的requestAnimationFrame来控制绘制批次,这种方式自由度更高:
var x = 0, y = 0; var space = 10; var batchSize = 15; var canvas; function setup() { canvas = createCanvas(window.innerWidth, window.innerHeight); background(0); strokeWeight(2); // 启动手动绘制循环 requestAnimationFrame(drawBatch); } function drawBatch() { stroke(255); for(let i = 0; i < batchSize; i++){ if(random() > 0.5) { stroke('#F26C4D'); line(x, y, x + space, y + space); } else { stroke(255); line(x, y + space, x + space, y); } x += space; if(x >= width) { x = 0; y += space; } if(y >= height){ return; // 画完了就停止 } } // 继续下一批绘制 requestAnimationFrame(drawBatch); } function draw() { // 留空,因为用了手动循环 }
这些方案都能安全地提升绘制速度,你可以根据自己是否需要动画效果来选择最合适的一种~
内容的提问来源于stack exchange,提问作者Se7eN
相关产品推荐
相关产品推荐

