【问题标题】:Why does my page fall into the infinite loop?为什么我的页面会陷入死循环?
【发布时间】:2021-05-27 01:25:18
【问题描述】:
function randomNumber(){
    var value;
    var flag = false;
    var tds = document.querySelectorAll('td');
    do{
        value = Math.round(Math.random() * (26 - 1) + 1);
        for(var t = 0; t < tds.length; t++){
            if(tds[t].innerHTML == value)
                flag = true;
        }
        if(!flag){
            return value;
        }
    }while(flag == true)
}

此函数返回一个随机数,用于新 td 的 innerHTML。如果存在与此代码生成的编号相同的其他 td,则循环再次开始。如果生成的数字是唯一的,我将其添加到新 td 的 innerHTML 中。但是我什至无法加载页面,因为我遇到了无限循环,但无论我多么努力,我都没有注意到这段代码的逻辑问题。

【问题讨论】:

  • flag设置为false的条件是什么?
  • 问:为什么我的页面会陷入死循环? A:可能是因为“value”显然总是等于“tds[t].innerHTML”,并且flag 永远不会保持“false”。建议:在调试器(例如 Chrome 开发者工具)中单步调试代码,并在遍历循环时查看“值”。

标签: javascript random html-table infinite-loop innerhtml


【解决方案1】:

一旦您的循环找到tds[t].innerHTML == value 的情况,它将flag 设置为true - 此时您将永远无法结束循环,因为您无法检查可以将flag 设置为的情况false,因此您的循环条件将始终为真。

这里有一个类似的例子,用一个数组来说明这一点。您可以看到,有时它会将数字添加到数组中(在它找到新值的情况下),但有时循环达到 5000 次迭代并退出(因为它从未找到新值),在这种情况下它会添加 undefined到数组,因为函数没有返回任何东西。

const arr = []
function randomNumber(){
    var value;
    var flag = false;
    var tds = arr
    var iterations = 0

    do {
        value = Math.round(Math.random() * (26 - 1) + 1);
        for(var t = 0; t < tds.length; t++){
            if(tds.includes(value))
                flag = true;
        }
        if(!flag){
            return value;
        }
        iterations += 1
        console.log(iterations)
    } while(flag == true && iterations < 5000)
}

for (let i = 0;i<20;i+=1) {
  arr.push(randomNumber())
}
console.log(arr)

【讨论】:

  • 你可以在函数内外访问arr - 拥有全局变量并不是很好 - 你真的不应该编写这样的代码。另外-为什么要迭代 5000 次,例如,如果所有 26 个 id 都已使用?当你可以检查你的函数是否有很小的机会返回它应该返回的任何东西时,你将失去超过 4800 次迭代
  • 注意点 - 这是一个示例,旨在说明原理并展示迭代如何继续进行,而不是最佳实践解决方案的实现。
  • 如果你在他的代码中得到了那个,并且那个代码进入了生产环境——那就太糟糕了
【解决方案2】:

当您的函数至少一次将flag 设置为 true 时,它​​就结束了 - 它再也不会将其设置为 false。为了修复它,我添加了一行代码。

function randomNumber(){
    var value;
    var flag = false;
    var tds = document.querySelectorAll('td');
    do {
        flag = false; // this line i added
        value = Math.round(Math.random() * (26 - 1) + 1);
        for(var t = 0; t < tds.length; t++){
            if(tds[t].innerHTML == value)
                flag = true;
        }
        if(!flag){
            return value;
        }
    }while(flag == true)
}

我也会为你写一些更高效的代码

function randomNumber(){
    var value;
    var found = false;
    var tds = document.querySelectorAll('td');
    var existingIds = [];
    tds.forEach(td => existingIds.push(td.innerHHML)); // fill up the ids
    do {
        value = Math.round(Math.random() * (26 - 1) + 1); // this line would make problems (comment below)
        if (existingIds.indexOf(value) === -1) found = true; // check if value can be found in existing ids and if found - set dount to true (you can also return from here, but i would rather user break (if there was more code after this line, than use retur in the middle of any loop;
    } while(found === false)

    return value;
}

对随机线的评论:

  • random() 返回从 0 到 1 的数字
  • 正如您所写 - 该值将是 1 到 26 之间的随机数(仅此值)。
  • 如果所有值都已被使用,那么我们的循环将不会结束(当 1 到 26 的所有值都已使用时,我们永远无法找到未使用的 1 到 26 之间的值。

可以做什么

  • 在这种情况下,您可以添加一些计数器(如 @Ben 所做的那样)并退出循环。
  • 或者您可以将数字 26 提高到更高
  • 您可以使用连续的数字(获取全部,取最大的一个,加 1 并将其作为新数字返回)

你当然可以找到一些其他的方法来解决这个问题

【讨论】:

  • 哇,我只是有点恼火,一切都那么简单。我在这上面花了大约 30 分钟。非常感谢。
  • 当你刚开始冒险编程/语言时,没问题
  • @Дмитрий Уткин - 请熟悉一个好的调试器,并养成单步调试代码的习惯。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-14
  • 1970-01-01
  • 2023-03-22
  • 2016-04-08
  • 2020-07-13
  • 2010-11-01
  • 1970-01-01
相关资源
最近更新 更多