当前位置: 首页 > 知识库问答 >
问题:

将网络摄像机视频渲染到画布时,超出了最大调用堆栈大小

羊渝
2023-03-14

我正在开发一个应用程序,其中将有两个参与者在一个会话中,他们可以进行视频通话。基本上,将有3个视频流。两名参与者和一名参与者将共享屏幕。这部分已经在工作了,但当用户单击录制按钮时,这3个视频应该在画布中输入,当暂停时,应该暂停。我尝试在画布中只渲染一个视频,以测试它是否有效“RangeError:在绘制函数上超出了最大调用堆栈大小”。

const draw = (canva, context) => {
    console.log('localVideoRef', localVideoRef)
    context.drawImage(localVideoRef.current, 0, 0, canva.clientWidth, canva.clientHeight);
    console.log('context draw', context)
    requestAnimationFrame(draw(canva, context))
  }
  const handleRecord = () => {
    const canva = document.createElement('canvas');
    canva.id = "canvas";
    const context = canva.getContext("2d");
    canva.width = canva.clientWidth;
    canva.width = canva.clientHeight;
    console.log('canva', context, canva);
    console.log('room', room);
    draw(canva, context);
    requestAnimationFrame(draw(canva, context)) # above error is shown here
    console.log('canva after drawing image', canva);
  }

错误出在这条行请求动画帧(绘制(canva,上下文))

更新(即使在停止记录后仍继续运行)

let canva, context = null;

function App(props) {
  const [record, setRecord] = React.useState('');
  React.useEffect(() => {
    canva = document.createElement('canvas');
    canva.id = "canvas";
    context = canva.getContext("2d");
    canva.width = canva.clientWidth;
    canva.width = canva.clientHeight;
  }, [])
  React.useEffect(() => {
    console.log('record', record);
    if (record === 'start' || record === 'resume') {
      requestAnimationFrame(() => draw(canva, context));
      console.log('canva after paint video', canva);
    } else {
      // when pausing or stoping recording, the painting should not be done. 
      console.log('this is the canva after paused or stopped', canva)
    }

  }, [record])
  const draw = (canva, context) => {
    context.drawImage(localMediaRef.current, 0, 0, canva.clientWidth, canva.clientHeight);
    console.log('painting');
    requestAnimationFrame(() => draw(canva, context));
  }
  const handleRecord = (type) => {
    setRecord(type)
  }
  render {
    return (

    )
  }
}

共有2个答案

岳浩穰
2023-03-14

嗨,这是因为您已经在Draw()代码中调用了Request estAnimationFrame()。因此该函数已经是递归的。通过调用DrawANDRequest estAnimationFrame(Draw),您将同时调用2个无限递归函数。只需删除Draw(),它就可以工作了:

const draw = (canva, context) => {
    console.log('localVideoRef', localVideoRef)
    context.drawImage(localVideoRef.current, 0, 0, canva.clientWidth, canva.clientHeight);
    console.log('context draw', context)
    requestAnimationFrame( (timestamp)=>draw(canva, context) ); // EDITED AS PER @Nicholas' answer.
}
const handleRecord = () => {
    const canva = document.createElement('canvas');
    canva.id = "canvas";
    const context = canva.getContext("2d");
    canva.width = canva.clientWidth;
    canva.width = canva.clientHeight;
    console.log('canva', context, canva);
    console.log('room', room);
    //draw(canva, context);        //just remove this line
    requestAnimationFrame( (timestamp)=>draw(canva, context) ) // EDITED AS PER @Nicholas' answer.
    console.log('canva after drawing image', canva);
}

有关requestAnimationFrame的详细信息,请参阅此文档。请注意,在他们的示例中,requestAnimationFrame(step)被调用,但step()没有被调用。

更新:正如@Nicholas所指出的,您需要将绘图功能包装在另一个功能中。如上所示。

至于为什么会导致最大调用大小超出错误,我其实有点困惑,当我在控制台上测试错误代码Chrome时候,反而得到了这个错误:

未捕获的TypeError:未能对“Window”执行“requestAnimationFrame”:作为参数1提供的回调不是函数。

这实际上在理论上是正确的。将requestAnimationFrame视为类似于setTimeoutsetTimeout使用类似于setTimeout(callback,time)的回调 requestAnimationFrame也是如此。

当您传递< code > requestAnimationFrame(draw(canva,context) )时,您基本上是在告诉requestAnimationFrame函数在其代码中的某个位置执行类似于< code>draw(canva,context)()的操作,而不是像您所期望的那样< code>draw(canva,context)。因此,它在我的Chrome控制台上抛出了< code > callback provided is not a function 错误。

但是对于超出最大调用堆栈的错误,我认为您的JavaScript引擎/编译器的请求AnimationFrame捕获错误,忽略它,然后继续按原样调用绘制函数。因此,这基本上可以翻译为:

draw = (canva, context)=>{
    ...
    draw(canva, context) //oh noes
}

这基本上是一个无限运行的递归函数。因此,超过最大调用堆栈错误。

齐威
2023-03-14
requestAnimationFrame(draw(canva, context))

这段代码将立即调用draw,然后draw的返回值将被传递到requestAnimationFrame。在draw中,重复这个过程,立即调用draw,它立即调用drew,等等。

相反,您希望将函数传递到请求动画帧中,如下所示:

requestAnimationFrame(() => draw(canva, context));
 类似资料:
  • 我正在使用我岳父让我建立的一个网站作为学习React的借口。我不是一个天生的JavaScript开发人员(更喜欢后端),我知道我下面的代码中可能有一些递归元素,但我就是看不到。谁能告诉我我做错了什么?

  • 这是的内容: 已删除几次,并尝试重新安装。无法理解是什么原因造成的,以及如何修复它。

  • 当我添加<代码>时 我得到错误 超过了最大调用堆栈大小 当然,如果我注释掉

  • 问题内容: 我有一台服务器,可能导致以下输出死亡: 但是,如果没有堆栈转储或跟踪,就无法确定这是无限递归还是只是链太大而已,更不用说问题函数在哪里了。 使用该选项运行Node 不仅使我的测试运行缓慢(正如人们期望的那样),而且没有重现该问题。 有人有任何解决方案或提示来深入了解此问题吗? 问题答案: 看来目前的答案是:站稳脚步,等待Node.js更新到新的V8版本,或者使用此Chromium项目错

  • 我正在尝试将文档批量插入MongoDB(因此绕过Mongoose并使用本机驱动程序,因为Mongoose不支持批量插入文档数组)。我这样做的原因是为了提高写作速度。 我收到错误RangeError: Maximum Call Stack Size Exceeded在console.log(err)在下面的代码: 类似于:https://stackoverflow.com/questions/243

  • 问题内容: 当我运行我的代码时,Node.js引发由过多的递归调用引起的异常。我试图将Node.js堆栈大小增加,但是Node.js崩溃而没有任何错误消息。当我不使用sudo再次运行此命令时,Node.js将输出。是否有可能在不删除递归调用的情况下解决此问题? 问题答案: 您应该将递归函数调用包装到 , 要么 函数使node.js有机会清除堆栈。如果您不这样做,并且有很多循环没有任何 真正的 异步