这个AJAX模式是内存泄漏吗?

时间:2013-06-04 11:03:26

标签: javascript jquery ajax angularjs

考虑Angular Js中非常标准的方法示例,它更新了视图:

$scope.fetchResults = function() {
    // Some local variable that will cause creation of closure
    var hugeData = serviceX.getMilionRecords();

    // Any call to any resource with success and error handlers.
    $http({
        method: "GET",
        url: "/rest-api/bulk-operation-x",
        params: { someParam: hugeData.length }

    }).success( function () {
        var length = hugeData.length;
        $scope.reportToUser("Success, that was " + length + " records being processed!";

    }).error( function () {
        var length = hugeData.length;
        $scope.reportToUser("Something went wrong while processing " + length + " records... :-(";
    });
};

这当然是假设的例子,但很好地显示了模式,可以将其描述为从AJAX回调中重用局部变量。

当然,在两个处理程序(successerror)中,我们正在创建一个hugeData的闭包,它直接从回调处理程序引用。

我的问题是:由于AJAX调用的结果只能成功或失败,重用这段代码会导致内存泄漏吗?我会回答“是”,但我无法在本地测试中可靠地证明这一点。

我想要一些更有经验的大师为我解释这个。我喜欢每天与Angular合作的人的回复,但欢迎任何jquery回复。

1 个答案:

答案 0 :(得分:4)

只要将$http()调用的结果(或任何有权访问hugeData的对象或函数)返回到fetchResults的外部范围,就会发生内存泄漏。

使用你的代码,没有任何大的内容直接暴露在fetchResults之外,$http()调用的结果将一直存在,直到它成功或失败,然后调用相应的回调,最后得到GC'ed

了解见解:http://jibbering.com/faq/notes/closures/#clIdRes

正如@ŁukaszBachman所观察到的,这并不能保证没有内存泄漏。对你的大对象或对范围内的大对象的回调的任何悬空引用都会引起祸患。

所以,让我们检查$q实施($http基于$q)。

如果选中https://github.com/angular/angular.js/blob/master/src/ng/q.js#L191,则可以看到延迟的resolve()方法首先将方法中的已注册回调列表复制到本地变量中:

var callbacks = pending;

随后取消外部pending(在defer级别定义)

pending = undefined;

然后,在下一个tick,执行回调。事实上,回调的参数本身可能是延迟的(为执行添加了进一步的延迟),事情可能会变得复杂,但最多可能会进入无限循环。 (那不好笑!)。如果你足够幸运不进入循环,那么在某些时候回调数组就会耗尽,然后就没有对回调列表的任何引用,所以它可用于GC。

但是

如果强迫他们,可能会出错。

您可以在回调中使用arguments.callee。

你也可以在键盘上扔啤酒。

如果你跳出窗外,除非你住在一楼,否则你可能会受伤。

快乐的EcmaScripting!