6

考虑这个 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 回复。

4

1 回答 1

4

一旦您将$http()调用结果(或任何有权访问 的对象或函数hugeData)返回到fetchResults.

使用您的代码,没有什么大的东西直接暴露在 之外fetchResults,并且$http()call 的结果将一直存在,直到它成功或失败,然后调用相应的回调,最后得到 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()deferred 的方法首先将注册的回调列表复制到一个变量中方法的本地:

var callbacks = pending;

随后使外部pending(在defer级别定义)无效

pending = undefined;

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

但。

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

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

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

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

快乐的 EcmaScripting!

于 2013-06-04T11:42:54.303 回答