JavaScript发布/子属性访问问题

JavaScript发布/子属性访问问题,javascript,underscore.js,publish-subscribe,Javascript,Underscore.js,Publish Subscribe,我在这里遇到了一个奇怪的问题,希望你们都能帮忙解决 项目详情 我正在为一个更大的应用程序开发一个简单的pub/sub实现,其中包括一个pubsub.subscribe\u once()方法。此方法允许创建一次性订阅,这意味着创建了一个通用订阅,然后一旦触发正确的“发布”事件并运行订阅回调,订阅将删除自身 subscribe_once: function(topic, func) { var sub = pubsub.subscribe(topic, func), old_

我在这里遇到了一个奇怪的问题,希望你们都能帮忙解决

项目详情 我正在为一个更大的应用程序开发一个简单的pub/sub实现,其中包括一个
pubsub.subscribe\u 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;
}
问题 我似乎对这个过程的记忆流有一些问题。(为了更好地理解下面的解释,我建议您边走边浏览下面的JSFIDLE演示。)我创建了一个subscribe_once('someevent')订阅,然后启动publish('someevent')。调用publish方法时,您希望看到的是topics哈希表包含一个“someevent”键,该键引用一个订阅对象数组。事实上,如果您引用主题[“someevent”],您会看到一个包含单个订阅的数组。但是,如果您引用主题,您会看到“someevent”键,但是数组是空的

通过注释出
pubsub.unsubscribe(sub)此问题已被消除,即使在运行
console.log(topics)
之后才启动此函数

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

演示:
任何帮助都将不胜感激!谢谢。

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

我会继续搜索一篇博客文章或是一些证实懒惰评估正在发生的事情

以防万一,我还没有说得很清楚,我所说的懒惰是指,在控制台中单击打开树视图之前,控制台不会收集对象的详细信息

我在Chrome工作

更新

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

我根据您的评论更新了小提琴:

请试试这个:

  • 运行fiddle并展开第一个console.log的对象树在发布事件触发之前,我将其设置为5秒超时,但您可以根据进入控制台并单击inspector open的速度将其设置为更长或更短

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

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

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

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

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

更新3


瞧,这是关于延迟评估的动议。

这将是一个严重的延迟评估:请参阅此更新,特别是文档底部的setTimeout环绕“unsubscribe”@即使没有支持文件,我也有一把小提琴,我认为它证实了正在发生的事情。见更新2。你完全正确。我想知道惰性评估中的值是多少?这似乎只会使跟踪对象的更改变得困难。请看下面的证据:@Squirkle我完全同意。这实际上在本周早些时候的一个主干应用程序上咬了我一口,尽管我直到研究了你的问题才意识到这是个问题。在另一个SO问题上提到的一种策略是将对象包装在
JSON.stringify
中,这会导致对象作为log is run.dup of进行计算