【问题标题】:setTimeout in object method continues to run after object is destroyed对象方法中的 setTimeout 在对象被销毁后继续运行
【发布时间】:2022-11-25 04:55:36
【问题描述】:

我有一个名为 Bullet 的类,它本质上是太空入侵者网页上的一个 div。当这颗子弹被“发射”时,我调用了一种逐渐将“子弹”向上移动到屏幕上的方法。

当子弹到达屏幕边缘时,我想从内存中删除整个子弹对象。但是,即使我删除了 setTimeout 循环(我认为),它仍会继续运行。

我相信有更好的方法来做到这一点!也许像这样运行循环是愚蠢的?

TIA

this.bulletmove = new CustomEvent("bulletmove",{detail:this.name});

...


/**
 * moves the bullet up the screen gradually
 */
fire(){

    var that = this;

    setTimeout(function(){
        that.moveUp();
        window.dispatchEvent(that.bulletmove);
        that.fire();

    },50);

}

该事件在控制器脚本中拾取,该脚本检查子弹是否已到达屏幕边缘,此时它已被删除:


window.addEventListener('bulletmove', function(evt) {
    checkCollision(evt);
},false);

...


/**
*Check if the bullet has gone off screen and deletes it
**/

function checkCollision(e){

    var bulletName = e.detail;
    
    var bullet = bullets[bulletName];

    //check if the bullet has gone off screen
    if (bullet.bottom < 0){
        bullet.destroy;
        delete bullets[e.detail];
        bullet=null;
    }
}

【问题讨论】:

  • 我认为更好的方法是让游戏循环在requestAnimationFrame 上运行,并根据经过的时间、是否与任何东西发生碰撞等来计算每个刻度的子弹位置。

标签: javascript settimeout


【解决方案1】:

您是否尝试过使用 clearTimeout 方法来阻止 setTimeout 触发?

https://www.freecodecamp.org/news/javascript-settimeout-how-to-set-a-timer-in-javascript-or-sleep-for-n-seconds/

const fireBullet = setTimeout(function(){
    that.moveUp();
    window.dispatchEvent(that.bulletmove);
    that.fire();

},50);

clearTimeout(fireBullet)

【讨论】:

    【解决方案2】:

    我认为您应该使用 setInterval 而不是再次调用 fire() - 通过调用该函数,将创建一个新的 setTimeout (使用新的处理程序);在删除 object 之前,您调用 obj.halt(),这会正确清除 setInterval。

    const obj = {
      name: "objName",
      bulletmove() {
        return new CustomEvent("bulletmove", {
          detail: this.name
        })
      },
      halt() {
        clearInterval(this.intervalHandler)
      },
      intervalHandler: null,
      fire() {
        const handler = setInterval(() => {
          // this.moveUp()
          // console.log("move up")
          window.dispatchEvent(this.bulletmove())
          // this.fire()
        }, 500)
        this.intervalHandler = handler
      },
    }
    
    let i = 0
    
    window.addEventListener('bulletmove', function(e) {
    
      // this if-else if mocks the collision detection
      // expected: log obj.name 5 times, then clear the interval,
      // then event should not be called anymore
      if (i < 5) {
        console.log(i, e.detail)
      } else if (i < 8) {
        obj.halt()
        console.log(i)
      } else if (i < 100) {
        console.log(i, e.detail)
      }
      i++
    })
    
    obj.fire()

    另一种方式

    如果 fire 方法返回其自己的“清除函数”,则更简洁的方法是,您可以在事件处理中使用它:

    const obj = {
      name: "objName",
      bulletmove() {
        return new CustomEvent("bulletmove", {
          detail: this.name
        })
      },
      fire() {
        const handler = setInterval(() => {
          // this.moveUp()
          // console.log("move up")
          window.dispatchEvent(this.bulletmove())
          // this.fire()
        }, 500)
        return () => clearInterval(handler)
      },
    }
    
    let i = 0
    
    const fireHandler = obj.fire()
    const eventHandler = (clearFn) => (e) => {
    
      // this if-else if mocks the collision detection
      // expected: log obj.name 5 times, then clear the interval,
      // then event should not be called anymore
      if (i < 5) {
        console.log(i, e.detail)
      } else if (i < 8) {
        clearFn()
        console.log(i)
      } else if (i < 100) {
        console.log(i, e.detail)
      }
      i++
    }
    
    const eventHandlerWithRemoveFn = eventHandler(fireHandler)
    
    window.addEventListener('bulletmove', eventHandlerWithRemoveFn)

    这种方法的缺点是你需要将每个对象的事件处理程序单独添加到window,它的好处是更易控制,代码更清晰(无需在对象中保存该处理程序)。

    【讨论】:

      猜你喜欢
      • 2011-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-23
      • 1970-01-01
      • 1970-01-01
      • 2012-04-24
      • 1970-01-01
      相关资源
      最近更新 更多