如何在 TypeScript 对象中使用 requestAnimationFrame?

13

我有一个对象,想在画布上进行绘制。它将使用requestAnimationFrame来启动游戏循环:

Contoso.ts

class Contoso
{
   //private ctx: CanvasRenderingContext2D;

   Initialize(ctx: CanvasRenderingContext2D) {
      //this.ctx = ctx;
      Render();
   }

   Render() {
      //...snip doing any actual drawing for the purpose of this question
      requestAnimationFrame(this.Render);
   }
}

app.ts

var contoso: Contoso;

contoso = new Contoso();
contoso.Initialize(canvas);

第一次调用Initialize时,requestAnimationFrame成功调用了Render

第二次requestAnimationFrame调用Render时,this.Renderundefined,导致程序崩溃。

似乎在第一次调用Initialize后,对象就被销毁了。

到底发生了什么?


如何维护 this 的视频:https://www.youtube.com/watch?v=tvocUcbCupA&hd=1 - basarat
4个回答

46

你已经丢失了this上下文。有两种可能的修复方法:

class Contoso
{
   /* ... */

   // Use () => syntax so Render always gets 'this' context
   // from the class instance
   Render = () => {
      //...snip doing any actual drawing for the purpose of this question
      requestAnimationFrame(this.Render);
   }
}

备选解决方案可能更加清晰,但缺点是会进行更多的分配(您可能不想为每个帧分配1个闭包!)

   Render() {
      //...snip doing any actual drawing for the purpose of this question
      requestAnimationFrame(() => this.Render);
   }

至少我知道我不是疯了——在我之前,有人遇到过这个问题。另一方面,修复后的版本足够可靠,以至于我可能不应该让一个类来维护渲染循环。我可能应该让全局变量调用该全局变量上的Render方法。 - Ian Boyd
2
@Ryan:第一个建议(即Render =()=>{...})非常好用。谢谢。 - omt66
是否需要取消动画帧以提高性能?如果是的话,请告诉我如何做到? - Umesh Patadiya

8

使用箭头语法(lambda):

requestAnimationFrame(() => this.Render());

是的,出于某种原因,这不起作用。渲染函数甚至没有被调用。 - Sentinel

4
我发现最好的方法是:
requestAnimationFrame(this.Render.bind(this));

.bind(this) 创建一个新的函数,使其 this 关键字设置为提供的值。

额外阅读


使用 bind 是危险的:https://basarat.gitbooks.io/typescript/docs/tips/bind.html - gregmatys
@gregmatys,你能详细说明一下bind的危险吗?你提供的链接页面已经不存在了,在该网站上搜索也没有明确反对绑定类方法的内容。在JavaScript中编写基于类的React代码时,this.fn = this.fn.bind(this)模式非常常见。我认为许多人在转向TypeScript时会遇到此类问题,因此更详细的解释会有所帮助。 - Simon Dell
https://hamednourhani.gitbooks.io/typescript-book/docs/tips/bind.html - gregmatys

2
在Firefox 49.0.1上,我使用Ryan Cavanaugh的解决方案时遇到了错误消息。

SyntaxError:bad method definition

对于以下代码行:

Render = ()=> {

我找到的解决方法如下:

class Test{

    constructor(){

        this.Render = ()=> {
            requestAnimationFrame( this.Render );
        };

    }
}

尝试使用 Render = () => { 而不是 this.Render = () => {。明确一点,我指的是在构造函数之外的 @Ryan 的代码。 - Kent Weigel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接