You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:09:27