1

我在这里遇到了一个奇怪的问题,希望大家能帮忙。

项目详情

我正在为一个包含pubsub.subscribe_once()方法的大型应用程序开发一个简单的发布/订阅实现。此方法可以创建一次性订阅,这意味着创建通用订阅,然后一旦触发正确的“发布”事件并运行订阅回调,订阅就会自行删除。

subscribe_once: function(topic, func) {
    var sub = pubsub.subscribe(topic, func),
        old_func = sub.func;

    // rewrite our subscription's method to remove itself after invocation
    sub.func = function() {
        // call the original function
        old_func.apply(this);
        // remove subscription from topic
        pubsub.unsubscribe(sub);
    };

    return sub;
}

问题

我似乎对这个过程的内存流有某种问题。(为了更好地理解下面的解释,我建议你边走边看下面的 jsfiddle 演示。)我创建了一个 subscribe_once('someevent') 订阅,然后触发 publish('someevent')。当调用 publish 方法时,您希望看到主题哈希表包含一个“someevent”键,它引用了一个订阅对象数组。事实上,如果您引用主题["someevent"],您会看到一个包含单个订阅的数组。但是,如果您引用主题,您会看到“someevent”键,但数组是空的!

通过注释掉pubsub.unsubscribe(sub);问题可以消除,即使这个函数直到我们运行之后才被触发console.log(topics)

此外,这似乎不是给定浏览器“线程”方式的问题console.log;尝试console.log(topics, topics[topic], topics, topics[topic]),您会得到相同的结果。

演示:http: //jsfiddle.net/4Ab6c/

任何帮助将不胜感激!谢谢。

4

1 回答 1

2

我仍在寻找一些文档来支持我,但我怀疑控制台中显示的对象正在对您的topics对象执行惰性评估。我在被推送到数组后添加console.log(topics)subscribe方法sub中,得到的结果与您的“但不在此处”日志相同。当我将小提琴的最后一行pubsub.publish('someevent')放入setTimeout其中并在回调运行之前打开对象树publish时,它会在数组中显示订阅,即使在回调运行后它也会保持这种状态。如果在回调运行之前我没有在控制台中打开对象树,那么我会看到空数组。

我将继续搜索博客文章或确认正在发生惰性评估的内容。

以防我不够明显,我的意思是懒惰,控制台不会收集对象的详细信息,直到在控制台中单击打开树视图。

我在 Chrome 中工作。

更新

我在 Firefox 上也发现了类似的行为。Firefox 识别出数组中有一个对象,但如果您在发布之前没有深入到数组中,那么数组的下钻将是空的。

我从您的评论中更新了小提琴:

http://jsfiddle.net/4Ab6c/2/

请试试这个:

  • 在发布事件触发之前运行小提琴并展开第一个 console.log 的对象树,我将其设置为 5 秒超时,但您可以根据您进入控制台的速度并单击检查员打开。

  • 您应该会按预期在数组中看到订阅对象。

  • 清除控制台并再次运行小提琴。这次不要打开对象检查器,直到发布事件触发并且所有代码都运行完毕。

  • 现在,当您打开第一个 console.log 的对象检查器时,您应该不会在数组中看到订阅事件。

更新 2 这是一个更简单的小提琴,它表现出相同的行为:

http://jsfiddle.net/4Ab6c/3/

如果你在第二个出现之前先展开,那么你会得到 foo: bar。如果你在第二个出现后第一个展开,你会得到 foo: baz。

更新 3

而且,瞧,另一个 SO 问题支持惰性评估的动议。

于 2012-09-14T21:11:28.937 回答