【问题标题】:Are closures causing a leak here?关闭是否会导致此处泄漏?
【发布时间】:2018-08-12 00:34:45
【问题描述】:

我有这个简单的设置来发出 AJAX 请求,并且在检查内存使用情况时,事件侦听器计数和堆使用会在快速混合按钮时上升。

显然,Chrome 中的事件侦听器计数是预期的,因为 GC 在分析内存时不理会它,但是堆呢?我在这里错过了明显的泄漏吗?

function handleResponse(oReq, success_func) {
  return function() {
    try {
      if (oReq.readyState === XMLHttpRequest.DONE) {
        if (oReq.status === 200) {
          var data = oReq.responseText;
          success_func(data);
        }
      }
    } catch (e) {
      console.log('Something went wrong: ' + e.description);
    }
  }
}

function makeRequest(name, method, data, success_func) {
  return function() {
    var oReq = new XMLHttpRequest();
    oReq.onreadystatechange = handleResponse(oReq, success_func);
    oReq.open(method, 'http://localhost:8080/' + name);
    oReq.send(data);
  }
}

function updateBookList(data) {
  console.log(typeof data);
  document.getElementById('ajax-content').innerHTML = data;
}

document.getElementById('show-books').addEventListener(
  'click', makeRequest('get_books', 'GET', null, updateBookList)
);

【问题讨论】:

  • 我不确定该代码是否会导致泄漏。我很好奇你为什么需要在那里关闭? makeRequesthandleResponse 返回闭包有什么好处?
  • 只是在这里玩,但想法是将它们用于更多请求(例如在其他事件处理程序上)
  • 您可以在没有闭包的情况下重用这些函数。也许尝试一下,看看你的堆问题是否消失。

标签: javascript memory-leaks garbage-collection


【解决方案1】:

每次调用返回函数的函数时,您都在创建新结构(闭包式)。它们将一直存在,直到它们中的所有变量和对象不再有任何引用。 GC 应该在一段时间后清除它们。

Javascript 的“原型”架构允许您从“主”创建实例。这使您可以管理事物的构造和销毁。

此外,它还允许您拥有多个不会相互冲突的唯一实例。

您可以利用 ES6 类结构。或者,这是原型中的伪“类”。

this.app = this.app || {};
(function(){

function Req(name, method, data, onSuccess){

    // this is kind of like the constructor
    this.success_func = onSuccess;

    // binding to "this" instance allows the XMLHttpRequest 
    // to trigger the result within the scope of "this" instance. 
    // Otherwise, the "onreadystatechange" method will execute 
    // within the window scope.
    this.handleResponse_bound = this.handleResponse.bind(this);

    this.makeRequest(name, method, data);

}

var p = Req.prototype;

    p.handleResponse = function() {
        try {
          if (this.oReq.readyState === XMLHttpRequest.DONE) {
            if (this.oReq.status === 200) {
              var data = this.oReq.responseText;
              this.success_func(data);
              this.cleanup();
            }
          }
        } catch (e) {
          console.log('Something went wrong: ' + e.description);
        }
    }

    p.makeRequest = function(name, method, data) {
        this.oReq = new XMLHttpRequest();
        this.oReq.onreadystatechange = this.handleResponse_bound;
        this.oReq.open(method, 'https://jsfiddle.net/' + name);
        this.oReq.send(data);
    }

    p.cleanup = function(){
        this.oReq = null;
        this.success_func = null;
        this.handleResponse_bound = null;
    }

    app.Req = Req;

}());

function updateBookList(data) {
  console.log(typeof data);
  document.getElementById('ajax-content').innerHTML = data;
}

document.getElementById('show-books').addEventListener(
  'click', new app.Req('get_books', 'GET', null, updateBookList)
);

【讨论】:

    猜你喜欢
    • 2017-12-05
    • 1970-01-01
    • 2023-03-11
    • 2020-01-29
    • 1970-01-01
    • 2013-04-04
    • 2013-01-10
    • 1970-01-01
    相关资源
    最近更新 更多