0

我一直在探索各种 MV* 框架中的模式,今天注意到一个奇怪的模式,这似乎会导致一些问题

模型原型。有财产collections: []

集合原型。有财产models: []

当一个集合获得一个新模型时,它被推入collection.models,但模型本身也被装饰以知道它是其成员的集合 - 即集合实例被推入model.collections

model.collections[0]包含 a 的集合也是 .models[0]具有集合属性的模型......等等。

最基本的:

var A = function() {
    this.collections = [];
},
    B = function() {
        this.models = [];
        this.add = function(what) {
            what.collections.push(this);
            this.models.push(what)
        };
    };


var model = new A();
var collection = new B();

collection.add(model);

这是有罪的一方:https ://github.com/lyonbros/composer.js/blob/master/composer.js#L310-313 ,然后进一步向下推入模型:https ://github.com/ lyonbros/composer.js/blob/master/composer.js#L781-784

我想会有一定程度的惰性评估——在需要之前不会使用东西。该代码 - 就其自身而言 - 有效。

但我也在通过 buster.js 编写测试,我注意到所有依赖的测试都在sinon.spy()生成InternalError: too much recursion(FF) 或RangeError: Maximum call stack size exceeded(Chrome)。捕获的 FF 甚至没有响应地崩溃,这是我以前从未遇到过的 buster 测试驱动程序 - 它甚至在我的午休时间使用了 3.5gb 的内存。

经过相当多的调试后,我取消了参考存储,突然间,一切又恢复正常了。诚然,删除spy()断言也有效,但这不是重点。

所以,问题是 - 有这样的代码,是否可以接受,浏览器将如何解释它,瓶颈是什么以及如何用指向它们所属集合的指针来装饰模型(可能是集合控制器和集合 uid或者其他的东西)。

将失败的 buster.js 测试的完整要点:https ://gist.github.com/2960549

4

2 回答 2

2

浏览器不在乎。问题是您使用的工具无法通过对象图检查循环引用链。这些是完全合法的,至少如果你想要它们并期待它们的话。

如果您想到一个对象及其属性,以及通过这些属性直接或间接引用的对象,那么该程序集就构成了一个。如果可以跟随参考并回到您开始的地方,那么这意味着该图有一个循环。语言允许循环绝对是一件好事。在给定系统中是否合适取决于相关代码。

因此,例如,如果图是循环的,则遍历对象图而不检查对象是否已访问过的递归函数肯定会触发“递归过多”错误。

于 2012-06-20T19:26:24.337 回答
1

只有两个对象相互引用(称为“循环引用”)。

var a, b = {a: a={b: b}};
// a.b: pointer to b
// b.a: pointer to a

根本没有递归。如果您遇到错误too much recursionMaximum call stack size exceeded错误,则需要有一个过于频繁调用的函数。例如,当您尝试克隆对象并递归属性而不关心循环引用时,可能会发生这种情况。您需要进一步查看代码,错误消息也应包含(非常长的)调用堆栈。

于 2012-06-20T19:29:42.330 回答