Javascript对象销毁事件处理程序

时间:2014-09-26 06:16:35

标签: javascript constructor

MyMapStaticObject

var PlaceViewModel = function(){
    MyMapStaticObject.addLayer(someLayer);
}

PlaceViewModel.prototype.addMarker = function(item){

}

我有一个 PlaceViewModel ,它有一个名为addMarker的函数,可以将标记添加到地图中。我将在不同的类中使用 PlaceViewModel new istances。

var inst = new PlaceViewModel();

初始化PlaceViewModel时,我正在通过 MyMapStaticObject 添加新图层。我应该在实例销毁时删除图层。

我可以处理javascript destroy事件吗?

2 个答案:

答案 0 :(得分:3)

Javascript没有销毁事件。它是一种垃圾收集语言,当不再有任何代码可以访问对象引用时,它将释放一个对象。当它释放对象时,它不会提供任何事件来通知它。

如果你想实现一些将删除图层的清理代码,那么你必须添加一个你可以在完成对象时调用的方法,这样你就可以调用该方法,它可以然后删除该方法中的图层。调用此方法必须是您手动操作(很可能它将被挂钩到代码中正在进行的其他操作的管理中,您可以在适当的时间通过该代码调用它。)

答案 1 :(得分:1)

在这里参加聚会有点晚,但是我想知道什么时候物体被销毁了。问题是JS没有任何内置方法来执行此操作。我想要这样做,以便可以将websocket事件添加到页面,然后在页面转到另一个页面时将其删除,当然我可以在页面加载部分中实现此功能,但是我有不同的框架,并且希望有一个更通用的解决方案对象破坏问题。 Javascript是一种垃圾收集语言,但是如果我们也可以附加一些生命周期事件,那还是很不错的。当然有代理服务器,但再次对这里无济于事,因为我需要知道代理服务器本身已被删除。

好吧,您确实有一个地方会发生销毁事件,而MutationObserver就是其中之一,大多数现代浏览器现在都支持该事件。它不是严格销毁,而是从DOM中添加和删除节点。但是总的来说,如果您有事件,您可能还会有一个可以附加的DOM节点,或者即使它不可见,也可以添加一个不可见的DOM元素。

因此,我有一个名为domDestroy(element, obj)的小函数,当它检测到element被删除时,它将检查obj是否具有destroy方法(如果存在)它会调用它。

现在我要了解的一个问题是,我是在一个隐藏的DOM节点中创建页面的,当然,当我将其放入可见的DOM节点时,由于要与不可见的DOM节点分离,然后再附加,我得到了删除。到可见的DOM。根本不是我们想要的。

解决方案非常简单,例如,当进行这种双重缓冲时,通常只需一步即可完成。隐藏当前页面,显示新页面。因此,我要做的是跟踪何时将其删除并保存在一个简单的Set中,然后还要跟踪添加的元素,如果该元素是Set中的一部分,我将删除它。然后,我只需要在下一个刻度上再次检查此Set,如果它仍然存在,它实际上已被删除,我们将调用该对象的destroy方法。

下面是一个简单的示例,基本上,如果右键单击并检查页面,则可以通过拖放来上下移动LI,这将导致DOM分离并重新连接。但是,如果您改为删除一个LI,您会注意到它说出delete then,因为它现在知道它没有重新连接到另一个DOM。

当然,需要注意的一件事是,如果您对DOM元素进行任何附加/分离,请尝试在同一时间间隔内执行此操作:IOW:请注意两者之间的异步操作。另外,您也可以使用分离的DOM来构建页面,在这里,您也可以轻松更改功能以解决此问题,基本上使用destroyObserver.observe(添加这些功能。

const dsy = "__dom-destroy-obj";
const destroyList = new Set();
let tm;

function cleanUp() {
  tm = null;
  for (const el of destroyList) {
    for (const d of el[dsy]) {
      d.destroy();
    }
  }
  destroyList.clear();
}

function checkDestroy(el) {
  if (el[dsy]) {
    for (const d of el[dsy]) {
      if (!d.destroy) {
        console.warn("No destroy, on dom-destroy-obj target");
      } else {
        destroyList.add(el);
        if (tm) return; //already a timer running
        tm = setTimeout(cleanUp, 1);
      }
    }
  }
  if (el.childNodes) for (const n of el.childNodes) checkDestroy(n);
}

function checkAdded(el) {
  if (el[dsy]) {
    destroyList.delete(el);
  }
  if (el.childNodes) for (const n of el.childNodes) checkAdded(n);
}

const destroyObserver = new MutationObserver(
  function (mutations) {
    for (const m of mutations) {
      if (m.removedNodes.length) {
        for (const i of m.removedNodes) {
          checkDestroy(i);
        }
      }
      if (m.addedNodes.length) {
        for (const i of m.addedNodes) {
          checkAdded(i);
        }
      }
    }
  }
);

destroyObserver.observe(document.body, {
  childList: true,
  subtree: true
});

function domDestroy(element, obj) {
  if (!element[dsy]) element[dsy] = new Set();
  element[dsy].add(obj);
}


//simple test.

for (const i of document.querySelectorAll("li")) {
  domDestroy(i, {
    destroy: () => console.log("destroy")
  });
}
<span>
From your browsers inspector, try moving the LI's, and deleting them.  Only when you delete the DOM node, should the destroy method get called.
</span>


<ul>
  <li>Re order</li>
  <li>Or delete</li>
  <li>Some of these</li>
</ul>