嵌套循环耗时太长,几乎崩溃了浏览器

时间:2015-08-24 16:41:07

标签: javascript json angularjs

我的应用正在检索json数据。 json文件有近千个单词,结构如下:

{"THEMES":{"THEME1":["ITEM1","ITEM2","ITEM3"],"THEME2":["ITEM1",...]...}}

该文件约为25kb。在我的应用程序的某个时刻,我需要比较哪个ITEM与哪个主题生成在角度ng-重复一个与单词相关的选定项目内。这是我的角度的一部分,它处理这些:

<div class="well">
    <div class="input-group" bindonce ng-repeat="word_in_list in words_list">
        <div class="form-group">
            <select>
                <option ng-selected="word_in_list.select == theme" ng-repeat="theme in themes" value="{{theme}}">{{theme}}</option>
            </select>
        </div>
        <div class="form-group">
            <input type="text" class="form-control" placeholder="{{word_in_list.input}}">
              <span class="input-group-addon">
                <input type="checkbox" ng-click="listControlWord($event, word_in_list.input, word_in_list.select)">
              </span>
        </div>
    </div>
</div>

重要的一部分是:

$http.get('json/word_bank.json')
    .success(function (result) {
        $scope.themes = Object.keys(result.TEMAS);
        for (var i = 0, z = $scope.themes.length; i < z; i++) {
            for (var j = 0; j < result.TEMAS[$scope.themes[i]].length; j++) {
                $scope.words_list.push({select: $scope.themes[i], input: result.TEMAS[$scope.themes[i]][j]});
            }
        }
    });

问题是浏览器需要大约两分钟来呈现信息,并且它经常会崩溃浏览器。循环工作正常,信息正在检索好,它只是需要的时间是不可接受的。如何优化这些循环?

3 个答案:

答案 0 :(得分:2)

你的算法是O(N ^ 2),除了特定领域的启发式方法之外,还没有办法解决这个问题。话虽这么说,你可以用不同的方式看待这一点。如果我正确理解问题,你真的想要连接数组。

以下是您要完成的performance test

不幸的是,我认为你不能使用最有效的方法(利用apply),但你可以使用这些技术的某种组合。通过连接所有数组,并保留关于连接数组中哪些索引与哪些&#34;键&#34;相关联的元数据,您可以将其减少为O(N)。

像...一样的东西。

<!doctype html>
<html lang="en">
    <head>
        <title>Test</title>
        <script src="d3.js" charset="utf-8"></script>
    </head>

    <body>
        <div id="divPerfTest"></div>

        <script>
            var result = {"THEMES":{"THEME1": ["ITEM1","ITEM2","ITEM3"],"THEME2":["ITEM1","ITEM2"]}};
            var keys = Object.keys(result.THEMES),
                master = [],
                masterBreaks = [],
                themeNames = [],
                word_list = [],
                theme, idx, key,
                breakIdx = 0,
                breakOffset = 0,
                outStr = "";


            for(idx = 0; idx < keys.length; idx++) {
                key = keys[idx];
                theme = result.THEMES[key];
                master = master.concat(theme);
                masterBreaks.push(theme.length);
                themeNames.push(key);
            }

            masterBreaks.push(master.length); // need the last break to exceed last index

            for (idx = 0; idx < master.length; idx++) {
                if (idx >= masterBreaks[breakIdx] + breakOffset) {
                    breakOffset += masterBreaks[breakIdx++];
                }

                word_list.push({
                    select: themeNames[breakIdx],
                    input: master[idx]
                });
            }

            for(idx=0; idx<word_list.length; idx++) {
                outStr += "[ " + idx.toString() + " ] Select: " + word_list[idx].select + ", Input: " + word_list[idx].input + "<br/>";
            }

            document.querySelector("#divPerfTest").innerHTML = outStr;
        </script>
</body>
</html>

但是,我认为更好的方法是更改​​数据架构。可以重构或按摩数据,使得主题的名称是对象的属性,而项目列表是同一对象的另一个属性,而不是使用定义不同主题的变量名称。然后你维护这些对象的列表......

{ THEMES: [
    { id: "THEME1",
      data: ["ITEM1", "ITEM2"] },
    { id: "THEME2",
      data: ["ITEM1", "ITEM2", "ITEM3"] }
}

答案 1 :(得分:0)

由于您只是循环遍历数组,您可以将其拆分为不同的部分,并使用计时器在迭代中处理每个部分而不是一次处理整个部分。

检查此链接: http://ejohn.org/blog/how-javascript-timers-work/

答案 2 :(得分:0)

好。我设法解决了将我的应用程序分页的问题。我从这里得到了代码: Code to tune long lists in AngularJs

希望这有助于其他人。最好的。