因为没有弱引用而导致Javascript问题

时间:2015-08-27 20:13:36

标签: javascript memory-leaks event-handling weak-references

让我们说我在javascript中创建了一个聊天系统。

var ChatController = function() {

    this.receiveMessageInteractor = new ReceiveMessageInteractor(this);

    // ReceiveMessageInteractor delegate

    this.didReceiveMessage = function(message) {
        // ...
    };

};

ChatController还会做一些与为消息创建html相关的其他内容,但这并不重要。

ChatController将自己设置为ReceiveMessageInteractor的代表,当新邮件到达时,didReceiveMessage会调用var ReceiveMessageInteractor = function(delegate) { this.observer = NotificationCenter.addObserver('DidReceiveMessageNotification' , function(data) { var message = data['message']; // format some message data delegate.didReceiveMessage(message) }); };

NotificationCenter

ReceiveMessageInteractor只是订阅了一个通知(这里的message类似于iOS),对数据做了一些格式化并将MenuController对象传递给了委托;

当聊天视图进入屏幕时(html被删除),我的ChatController停止了指向ReceiveMessageInteractor的指针,在这种情况下,我希望将其删除,以及observerReceiveMessageInteractor

问题是Javascript没有弱引用,因此ChatController持有指向ChatController的指针,即使ReceiveMessageInteractor没有指向{{1}的指针我的ChatController仍然存活,因为通知回调是一个指向它的指针(delegate)。 因此,即使ReceiveMessageInteractor已停止存在,当ChatController停止指向它时,我的MenuController仍然不会消失(因为我在通知中无法提供弱引用)回调)。

如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

  

如何解决这个问题?

通过了解JavaScript。问题不在于" Javascript没有弱引用",问题在于你不知道如何在没有它们的情况下工作,因为你来自一种拥有它们的语言。

您如何删除其他任何本身没有弱引用的语言的引用?让我们说C ++。你会像每个人一样,包括编译器/垃圾收集器/弱引用的实现者,你已经习惯了:你自己清理。

function ChatController() {

    this.receiveMessageInteractor = new ReceiveMessageInteractor(this);

    // ReceiveMessageInteractor delegate

    this.didReceiveMessage = function didReceiveMessage(message) {
        // ...
    };

    this.destroy = function destroy() {
        this.receiveMessageInteractor.destroy();
    };

};

function ReceiveMessageInteractor(delegate) {

    function callback(data) {
        var message = data.message;
        // format some message data

        delegate.didReceiveMessage(message);
    }

    this.observer = NotificationCenter.addObserver('DidReceiveMessageNotification', callback);

    this.destroy = function destroy() {
        // Or however you NotificationCenter works, I don't know
        NotificationCenter.removeObserver('DidReceiveMessageNotification', callback);
    };

};

观察者模式意味着资源管理,即使它并不明显(如何观察"关系是资源?)。获取并发布。没有手握。

另外,请注意样式的变化。请学习语言,使用原型,虽然不是每个人都同意我的观点,但不要在构造函数中分配方法。

修改:我忘了添加:ReceiveMessageInteractor?真? MessageReceiver或其他什么东西出了什么问题?

答案 1 :(得分:1)

你的问题不在于没有弱引用。您的所有对象都会继续有一个硬参考,所有这些都来自您的NotificationCenter

NotificationCenter引用了数据处理程序,该数据处理程序具有对其父ReceiveMessageInteractor实例的闭包访问权限,以及对delegate变量的访问权限。从其他位置删除对delegate的引用不会破坏匿名函数对它的访问权限,因此它会保留。

您需要做的是向每个被删除时调用的Controller添加.cleanup()方法。

ChatController.cleanup()方法中,您可能希望调用一个方法来移除观察者,类似于this.receiveMessageInteractor.observer.unsubscribe()

应在NotificationCenter中定义.unsubscribe()方法,并删除您在function(data) { ... }中定义的.addObserver()方法,该方法不受任何数据结构的限制(或更深层次)。

这与Facebook在其React框架+ Flux架构中使用的模式相同。每个组件都有一个componentWillUnmount()方法,可以帮助您清理数据事件处理程序,就像您的一样。