【问题标题】:XMLHttpRequest loop memory leakXMLHttpRequest 循环内存泄漏
【发布时间】:2013-12-17 06:12:04
【问题描述】:

我正在尝试根据有关 ajax URL 的信息检查许多项目。但是当我在浏览器中运行此功能时,内存使用量超过 2 gigs,然后浏览器崩溃(Chrome、Firefox)。我究竟做错了什么? items 变量非常大 - >200 000 并且还包含一些大字符串。

var items = [1,2,3,4,5,6,7,8,9,10,...,300000]
var activeItems = {}

function loopAjax(){
    for (i=0; i < items.length; i++) {
        var currItem = items[i];
        var request = new XMLHttpRequest();
        var found = 0

        request.open("GET", "/item=" + currItem);
        request.onreadystatechange = function() {
            if (request.readyState == 4 && request.status == 200) {
                var response = JSON.parse(request.responseText);
                var active = response[0].active;
                if (active) {
                    console.log("FOUND ACTIVE! " + currItem);
                    activeItems[found] = {"active": true, "item": currItem};
                    found++;
                }
            }
        }
        request.send();
    }
}

【问题讨论】:

  • ...300000 是问题所在。您需要重新设计解决此问题的方式
  • 这是一个糟糕的设计。想想你在做什么。向服务器发出 200,000 个请求!?您没有任何延迟,因此您只需强制浏览器将呼叫排队即可。没有休息。服务器应该在一个调用中处理多个项目。不止一个。您需要考虑排队呼叫。
  • 哇,对服务器的请求实在是太多了。为什么会有这么多请求?
  • 相关:Javascript closure inside loops - simple practical examplevars 在 JavaScript 中是 programfunction-范围,而不是块范围。因此,您只声明了 1 个request 变量供for 循环的所有迭代共享。而且,由于 Ajax 是异步的,request 的值会在调用onreadystatechange 之前发生变化,并且可以验证任何requests 的状态。
  • ... 这意味着请求状态/状态可能永远不会被满足。

标签: javascript jquery ajax xmlhttprequest


【解决方案1】:

谢天谢地,浏览器停止运行并死机。如果没有,您只是创建了拒绝服务攻击!

需要重新解决问题。您最好创建一个包含一堆请求的状态机。这样你一次只能说 5 个并发请求。

function ItemChecker(sample_size, max_threads) {
  this.sample_size = sample_size;
  this.max_threads = max_threads;
  this.counter = 0;
  this.activeItems = [];
  this.isRunning = false;
  this.running_count = 0;
}

ItemChecker.prototype.start = function start() {
  this.isRunning = true;
  while (this.running_count < this.max_threads) {
    this.next();
  }
  return this;
};

ItemChecker.prototype.stop = fucntion stop() {
  this.isRunning = false;
  return this;
};

ItemChecker.prototype.next = function next() {
  var request, item_id, _this = this;

  function xhrFinished(req) {
    var response;
    if (req.readyState !== 4) {
      return;
    }

    _this.counter--;

    if (req.status === 200) {
      try {
        response = JSON.parse(request.responseText);
        if (response[0].active) {
          _this.activeItems.push({
            active: true,
            item: item_id;
          });
        }
      } catch(e) {
        console.error(e);
      }

      // When finished call a callback
      if (_this.onDone && _this.counter >= _this.sample_size) {
        _this.onDone(_this.activeItems);
      }
    }
    else {
      console.warn("Server returned " + req.status);
    }
  }

  if (!this.isRunning || this.counter >= this.sample_size) {
    return;
  }

  item_id = this.counter;
  this.counter++;

  request = new XMLHttpRequest();
  request.onreadystatechange = xhrFinished;
  request.open("GET", "item=" + item_id);
  request.send();
};

ItemChecker.prototype.whenDone = function whenDone(callback) {
  this.onDone = callback;
  return this;
};

这可能有用吗?没试过真的。但你可以这样称呼它:

var item_checker = new ItemChecker(300000, 5);
item_checker.whenDone(function(active) {
  // Do something with active
}).start();

【讨论】:

  • 我当然会真的这么做。我会使用 Promise 来做到这一点。
  • 感谢您的回答。我找到了一种使用 setTimeout 限制并发请求的方法,但这看起来更好,我会尝试一下。反正那是我自己的机器 :)
  • 只是警告你 XMLHttpRequests 是异步的。在逻辑中添加 setTimeouts 只会使复杂性变得更糟。
猜你喜欢
  • 1970-01-01
  • 2014-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-13
  • 2018-05-13
  • 2014-12-28
  • 2014-09-08
相关资源
最近更新 更多