流星 - 探测无限循环

时间:2017-04-24 10:00:39

标签: javascript meteor halting-problem

这是Meteor应用程序用于计算事物的一些代码(带有相关数据)的本质。计数可以链接在一起,以便可以增加另一个:

// The counting and linking code.
Meteor.methods({
    'counts.increment'(countId) {
        const count = Counts.findOne(countId);
        Counts.update(countId,{ $inc: { count: 1 } })
        Meteor.call('counts.check-links',count._id);
    },
    'counts.check-links'(countId){
        var count = Counts.findOne(countId);
        count.links.forEach(function (linkId) {
            updated = false;
            const link = Links.findOne(linkId);
            const primary = Counts.findOne(link.primary);
            const secondary = Counts.findOne(link.secondary);
            if (primary.count == link.level) {
                updated = true;
                Counts.update(secondary._id, {$inc: {count: 1}});
            }
            if (updated) {
                Meteor.call('counts.check-links',secondary._id);
            }
        })
    }
})

// Some data...
Count: {
  _id: 1,
  value: 0,
  name: A,
  links: [3]
}

Count: {
  _id: 2,
  value: 0,
  name: B,
  links: [4]
}

Link: {
  _id: 3,
  primary: 1,
  secondary: 2
}

Link: {
  _id: 4,
  primary: 2,
  secondary: 1
}

因此,如果调用Meteor.call('projects.increment',1),则此代码将崩溃,因为每个计数都链接到另一个。检测这样的设置可能相当困难,因为可能存在非常复杂的计数排列,并且链路也可以减少(设置为零)每N计数和c运行。和C。但是,为了提出这个问题并不重要。

我想到的一种可能性是在counts.check-links内添加一个计数器,它会在任意数量的循环之后停止执行,例如5.据推测,为了防止篡改,该计数器的值必须存储在数据库中并通过Meteor方法进行处理。它需要在任何check-links次调用序列结束时重置。

我不确定这是不是最好的想法,或者如果是这样,怎么可能是一个好方法来实现它,所以我很想知道是否有人有任何建议。

1 个答案:

答案 0 :(得分:1)

您可以创建一组已经访问过的所有对象(“计数”);因此,如果您按照指向此类对象的链接,则可以避免再次处理它,从而进入无限递归。

编辑:示例 我不熟悉meteor,所以如果它不能按预期工作,请原谅...这是所有允许指向对象引用的编程语言的常见问题,并且解决方案遵循类似的模式。 / p>

// The counting and linking code.
Meteor.methods({
  ...
'counts.check-links'(countId, alreadyVisited){

    if (!alreadyVisited) alreadyVisited = {};
    if (alreadyVisited[countId]) return;
    alreadyVisited[countId] = true;

    var count = Counts.findOne(countId);
    count.links.forEach(function (linkId) {
        updated = false;
        const link = Links.findOne(linkId);
        const primary = Counts.findOne(link.primary);
        const secondary = Counts.findOne(link.secondary);
        if (primary.count == link.level) {
            updated = true;
            Counts.update(secondary._id, {$inc: {count: 1}});
        }
        if (updated) {
            Meteor.call('counts.check-links',secondary._id, alreadyVisited);
        }
    })
}