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

Łuk*_*man 6 javascript ajax jquery 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... :-(";
    });
};
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

rew*_*ten 4

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

\n\n

对于您的代码,没有什么大的东西直接暴露在 之外fetchResults,并且调用的结果$http()将一直存在,直到成功或失败,然后调用相应的回调,最后进行 GC。

\n\n

有关见解,请参阅:http://jibbering.com/faq/notes/closures/#clIdRes

\n\n

正如 @\xc5\x81ukaszBachman 所观察到的,这并不能保证不存在内存泄漏。任何对大对象或范围内具有大对象的回调的悬空引用都会导致灾难。

\n\n

那么,让我们检查一下$q实现($http基于$q)。

\n\n

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

\n\n
var callbacks = pending;\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
pending = undefined;\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后,在下一个时钟周期,执行回调。由于回调的参数本身可能是延迟的(进一步增加执行延迟),事情可能会变得复杂,但最多可能会进入无限循环。(这并不好笑!)。如果你足够幸运没有进入循环,那么在某个时刻回调数组就会耗尽,然后就没有任何对回调列表的引用,因此它可用于 GC。

\n\n

但。

\n\n

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

\n\n

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

\n\n

你也可以把啤酒扔到键盘上。

\n\n

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

\n\n

祝 Ecma 脚本编写愉快!

\n