0

我实现了一个小脚本来测试 requestAnimationFrame 并生成“未捕获 RangeError:超出最大调用堆栈大小”错误..这是代码

<html>
    <head>
        <meta charset="utf-8">

        <script>

            window.onload=function(){
            if (document.createElement("canvas").getContext){
                //alert("browser supports canvas");
                //console.log(document.getElementById("canvas").getContext);
                canvas = document.getElementById("canvas");
                shape = new shapes();
                shape.drawball(canvas,5,"red");




                }
            };


function shapes(){
    this.drawtriangle = function(canvas){
        triangles = new triangle(0,0,0,200,200,200);
        triangles.draw(canvas.getContext('2d'));    
    }

    this.drawball = function(canvas,radius,color) {
        ball = new Ball(radius,color);
        ball.drawBall(canvas.getContext('2d'),canvas);
    }
}


function coordinates(x1,y1){
    this.x = x1;
    this.y = y1;
}





function angle(angle){
    this.angle = angle;
}

function Ball(radius,color){
    this.origin = new coordinates(100,100);
    this.radius = (radius === "undefined" ) ? 5 : radius;
    this.color = (color === "undefined") ? red : color;
    this.rotation = 0;
    this.index  = 0;
    this.angles = new angle(0);
    this.speed = 10;
}

Ball.prototype.drawBall = function (context,canvas){

    context.fillStyle = this.color;
    context.strokeStyle = "blue";
    context.rotate(this.rotation);
    context.beginPath();
        context.arc(this.origin.x,this.origin.y,this.radius,0,(Math.PI*2),true);
    context.closePath();
    context.fill();
    context.stroke();   this.animate(context,canvas);
}

Ball.prototype.animate = function (context,canvas){
        var that = this;console.log(".......");
        var time = new Date().getTime() * 0.002;

                this.origin.x = Math.sin( time ) * 96 + 128;

                this.origin.y = Math.cos( time * 0.9 ) * 96 + 128;
//context.clearRect(0,0,1000,1000);
        console.log("Animating ... ");  
        this.origin.x = this.origin.x + this.speed; 
        this.origin.y = this.origin.y + this.speed; 
        this.angles.angle = this.angles.angle + this.speed;

        window.webkitrequestAnimationFrame(that.drawBall(context,canvas));

}



        </script>
        <style>

            body {
                background-color: #bbb;
                }       
            #canvas {
                background-color: #fff;
            }
        </style>
    </head>

    <body>
        <canvas id="canvas" width="1000px" height="1000px">
            Your browser dows bot suppoet canvas

        </canvas>



    </body>
</html>

我从网上得到了另一个代码,虽然它有递归,但它工作正常。

<!DOCTYPE HTML>

<html lang="en">

    <head>

        <title>RequestAnimationFrame.js example</title>

    </head>

    <body>

        <script >/**
 * Provides requestAnimationFrame in a cross browser way.
 * http://paulirish.com/2011/requestanimationframe-for-smart-animating/
 */

if ( !window.requestAnimationFrame ) {

    window.requestAnimationFrame = ( function() {

        return window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame || // comment out if FF4 is slow (it caps framerate at ~30fps: https://bugzilla.mozilla.org/show_bug.cgi?id=630127)
        window.oRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) {

            window.setTimeout( callback, 1000 / 60 );

        };

    } )();

}</script>

        <script>



            var canvas, context;



            init();

            animate();



            function init() {



                canvas = document.createElement( 'canvas' );

                canvas.width = 256;

                canvas.height = 256;



                context = canvas.getContext( '2d' );



                document.body.appendChild( canvas );



            }



            function animate() {



                requestAnimationFrame( animate );

                draw();



            }



            function draw() {



                var time = new Date().getTime() * 0.002;

                var x = Math.sin( time ) * 96 + 128;

                var y = Math.cos( time * 0.9 ) * 96 + 128;



                context.fillStyle = 'rgb(245,245,245)';

                context.fillRect( 0, 0, 255, 255 );



                context.fillStyle = 'rgb(255,0,0)';

                context.beginPath();

                context.arc( x, y, 10, 0, Math.PI * 2, true );

                context.closePath();

                context.fill();



            }



        </script>



        <div style="width:256px">

            <a href="javascript:location='view-source:' + window.location.href;">view source</a><br /><br/>



            <a href="http://dev.chromium.org/developers/design-documents/requestanimationframe-implementation">requestAnimationFrame()</a> allows modern browsers to stop drawing graphics when a tab or window is not visible. Improving overall performance and batteries on mobile devices.<br /><br />



            <a href="https://gist.github.com/838785">RequestAnimationFrame.js</a> emulates the basic usage for old browsers.

        </div>

    </body>

</html>

什么可能导致此错误,我该如何解决?

4

1 回答 1

2

Ball.animate调用Ball.drawBall,反之亦然。因此,在任何一个完成执行之前,它们都会相互调用,直到“调用堆栈”大小超过其限制(导致错误)。

代替

ball.drawBall(canvas.getContext('2d'),canvas);

尝试

setInterval(function () { ball.animate(canvas.getContext('2d'),canvas); }, 1000/60);

并删除

this.animate(context,canvas);

Ball.prototype.drawBall

你的代码有很多很多问题,但这就是你问的问题。


我已经解释了简单的错误。我的注释在/* */评论中。还有格式和样式错误,我已经省略了。

<html>
<head>
<meta charset="utf-8">

<script>
window.onload=function(){
  if (document.createElement("canvas").getContext){
    //alert("browser supports canvas");
    //console.log(document.getElementById("canvas").getContext);
    canvas = document.getElementById("canvas");
    shape = new shapes();

    /* drawball should be called by a run() function, or similar */
    shape.drawball(canvas,5,"red");
  }
};

/** 
 * Is this supposed to be a singleton, or perhaps a module?
 * otherwise, you should use prototype to define these methods
 */
function shapes(){
  this.drawtriangle = function(canvas){
    /* triangles isn't defined in this file? */
    triangles = new triangle(0,0,0,200,200,200);

    /* I'd store a reference to context as a property of the function (class)
     * aka a "static variable" */ 
    triangles.draw(canvas.getContext('2d'));    
  }

  this.drawball = function(canvas,radius,color) {
    ball = new Ball(radius,color);

    /* same here */
    ball.drawBall(canvas.getContext('2d'),canvas);
  }
}

/**
 * this is reasonable, but don't pluralize a class name unless you mean it
 * I'd maybe call it "Point" or "Vec2d"
 */
function coordinates(x1,y1){
  this.x = x1;
  this.y = y1;
}

/* so you'd use this object as angle.angle?? Just store it as a scalar.*/
function angle(angle){
  this.angle = angle;
}

/* This is correct, I'm sure it's also copy/pasted */
function Ball(radius,color){
  this.origin = new coordinates(100,100);
  this.radius = (radius === "undefined" ) ? 5 : radius;
  this.color = (color === "undefined") ? red : color;
  this.rotation = 0;
  this.index  = 0;
  this.angles = new angle(0);
  this.speed = 10;
}

/**
 * Ball.drawBall()? I'd use Ball.draw()
 * I'd again store context in the function object, and you don't need to
 * pass canvas
 */
Ball.prototype.drawBall = function (context,canvas){
  context.fillStyle = this.color;
  context.strokeStyle = "blue";
  context.rotate(this.rotation);
  context.beginPath();
  context.arc(this.origin.x,this.origin.y,this.radius,0,(Math.PI*2),true);
  context.closePath();
  context.fill();
  context.stroke();

  /* There is no reason to have your whole animation call here,
   * there should only be code to _draw_ the _ball_ (like the function says) */
  this.animate(context,canvas);
}

/* This makes sense for a singleton Ball, but in this case animate should be
 * on a containing object. The Ball doesn't animate anything, the App does */
Ball.prototype.animate = function (context,canvas){

  /* I can't explain this. I'm 99.999% sure it's not what you want. */
  var that = this;console.log(".......");

  var time = new Date().getTime() * 0.002;

  this.origin.x = Math.sin( time ) * 96 + 128;

  this.origin.y = Math.cos( time * 0.9 ) * 96 + 128;
  //context.clearRect(0,0,1000,1000);
  console.log("Animating ... ");  
  this.origin.x = this.origin.x + this.speed; 
  this.origin.y = this.origin.y + this.speed; 
  this.angles.angle = this.angles.angle + this.speed;

  /* you complete your cycle here (animate calls drawBall and vice versa) */
  window.webkitrequestAnimationFrame(that.drawBall(context,canvas));

}
</script>
<style>

body {
  background-color: #bbb;
}       
#canvas {
  background-color: #fff;
}
</style>
</head>
<body>
<canvas id="canvas" width="1000px" height="1000px">
Your browser dows bot suppoet canvas
</canvas>
</body>
</html>
于 2012-05-30T06:04:41.073 回答