【问题标题】:Jquery crashes while parsing large csv file解析大型 csv 文件时 Jquery 崩溃
【发布时间】:2015-03-09 09:24:53
【问题描述】:

我在一个教程网站上找到了这个 jquery 函数,该函数接受 csv 文件输入并将其制表。我尝试提供一个大的 csv 文件(10,000KB),但我的浏览器崩溃了。我看到有一个名为 papa 的解析器库来处理这个问题,但是有没有其他方法可以防止我的浏览器在执行此操作时崩溃?

以下是相关代码:-

 $("#upload").bind("click", function () {

        var regex = /^([a-zA-Z0-9\s_\\.\-:])+(.csv|.txt)$/;
        if (regex.test($("#fileUpload").val().toLowerCase())) {
                            var reader = new FileReader();
                reader.onload = function (e) {
                    var table = $("<table id='mytable' class='table table-striped table-bordered'/>");
                    var rows = e.target.result.split("\n");
                    text1=e.target.result;
                    var csvString = $.trim(text1);
                    var csvRows    = csvString.split(/\n/);
                    var csvHeaders = csvRows.shift().split(';');
                    var headerstr=String(csvHeaders);
                    var count = (headerstr.match(/,/g) || []).length+1;
                    for (var i = 0; i < rows.length; i++) {
                        var row = $("<tr />");
                        var cells = rows[i].split(",");
                        for (var j = 0; j < count; j++) {

                            if(cells[j]){
                            var cell = $("<td/>");

                            cell.html(cells[j]);
                            }
                            else{
                            var cell = $("<td class='info'/>");
                            cell.html("empty");}
                            row.append(cell);

                        }
                        table.append(row);

                    }


                    $("#dvCSV").html('');
                    $("#dvCSV").append(table);
                }

    });

如何在不使浏览器崩溃的情况下实现此功能?提前致谢。

【问题讨论】:

  • 尝试使用分析器(Chrome 的开发工具有一个)并找出占用所有内存的原因。我很确定 for 循环中的那些 vars 特别糟糕。
  • 嗨@Sergiu ..删除for循环内的变量没有帮助。我正在使用 firefox .. :( 我只需要这个功能完好无损,但不会让我的浏览器崩溃
  • 我并没有说删除循环内的vars 可以解决这个问题。我的意思是这样做会特别消耗内存。您正在做 很多 其他对内存和 CPU 效率不高的事情。在循环内重复构建相同的 HTML 结构也很糟糕。尝试在循环之外构建它,只在其中注入数据,然后将其附加到 DOM。还要尝试一次添加一批表格行,而不是一次添加一个。 jQuery 知道$(element).append([list of nodes]) 并使用文档片段对其进行优化。
  • 重点是事件,尽管 PapaParse 处理您负责显示它的数据。如果我是你,我会首先考虑分页。如果分页不正常,那么你真的需要优化你的 jQuery 代码。
  • 嗨。我明白。我必须重写此代码以在 for 循环之外重新创建 html。您能否用一段支持代码添加您的建议作为解决方案?

标签: javascript jquery csv


【解决方案1】:

解决这个问题的两个大问题:

1) CSV 解析器。 Papa Parse 很棒。它支持工作线程并且是一个流解析器 - 处理大文件的唯一方法。

2) 显示数据的方式。简单地输出表格中的每一行是行不通的。我两次崩溃我的电脑试图想出一个可行的解决方案。这样做的唯一方法以及基本上任何处理大文件的系统都使用的方法是使用虚拟化列表。我最终使用了this one。简单,代码通俗易懂。

这是我的 JS:

$("#fUpload").bind("change", function(evt) {
    var bigFile = evt.target.files[0];
    var rows = [];
    Papa.parse(bigFile, {
        delimiter: ",",
        newline: "\n",
        header: false,
        dynamicTyping: false,
        worker: false,
        chunk: function(results) {
            rows.concat(rows, results.data);
        },
        complete: function() {
            var list = new VirtualList({
              h: 300,
              itemHeight: 30,
              totalRows: rows.length,
              generatorFn: function(row) {
                  var el = document.createElement("div");
                  el.innerHTML = "<p>ITEM " + row + ' -> ' + rows[row].join(' - ') + "</p>";
                  return el;
              }
            });
            document.body.appendChild(list.container)
        }
    });
});

HTML 包含以下输入: &lt;input type="file" id="fUpload" /&gt;

我是如何配置爸爸的:

  • delimiternewline:如果您允许它尝试检测它们,它将失败或需要更长时间;

  • worker:这将产生一个工作进程。它会更慢会保持 UI 响应(UI 线程不会做任何工作)。您可能希望在生产中将此设置为true。 (由于浏览器跨域安全协议,这在 JSFiddle 上不起作用!);

  • chunk:不是为每个解析的行调用一个回调,而是为一组更大的行设置一个回调。这样更快;

虚拟列表配置是默认配置。

你可以运行它here

我测试了一个 9.4 MB 的 CSV 文件,其中包含 1,Foo,100 在每一行重复。

Here's the same but using a table输出数据并在VirtualList的totalRows中添加-1以补偿实际长度。

【讨论】:

  • 感谢您提供有效的解决方案。是否可以制表此输出?而且,如何将 papa parse 链接到我的代码?有没有CDN镜像可以做??
  • 您可以从他们的网站下载 Papa Parse:papaparse.com 它托管在 GitHub 上。
  • 我下载了 papaparse 文件夹并将其添加到我的工作文件夹中。但它不起作用。
  • 你必须在你的 HTML 中加载它:&lt;script src="lib/papaparse.js"&gt;&lt;/script&gt; 可能还有&lt;script src="lib/vlist.js"&gt;&lt;/script&gt;...(其中lib/whatever.js 是 js 文件的相对路径)。另请参阅我对表格版本的更新答案。
  • 感谢更新代码我尝试将 js 文件放在我正在使用的 html 文档旁边,还将它添加到目录中,但 papaparse.js 和 vlist.js 无法识别.. :(我可以看到它在小提琴中运行良好,但我无法在我的 html 页面中做到这一点
【解决方案2】:

我建议您使用 console.log('...') 来确定它在哪里锁定/中断,可能在第一个变量(行,csvString)中,因为大小。所以,你可以知道从哪里攻击。

如果不在 before 循环块中,那么我认为在这种情况下使用 jquery 太昂贵了,所以尝试直接 DOM 方法(至少在循环内):

$("#upload").bind("click", function () {
    var regex = /^([a-zA-Z0-9\s_\\.\-:])+(.csv|.txt)$/;
    if (regex.test($("#fileUpload").val().toLowerCase())) {
                        var reader = new FileReader();
            reader.onload = function (e) {
                var table = $("<table id='mytable' class='table table-striped table-bordered'/>");
                var rows = e.target.result.split("\n");
                text1=e.target.result;
                var csvString = $.trim(text1);
                var csvRows    = csvString.split(/\n/);
                var csvHeaders = csvRows.shift().split(';');
                var headerstr=String(csvHeaders);
                var count = (headerstr.match(/,/g) || []).length+1;
                for (var i = 0; i < rows.length; i++) {
                    var row = document.createElement("tr");
                    var cells = rows[i].split(",");
                    for (var j = 0; j < count; j++) {
                        var cell = document.createElement("td");
                        if(cells[j]){

                        cell.appendChild(document.createTextNode(cells[j]));
                        }
                        else{
                            cell.setAttribute('class','info');
                            cell.appendChild(document.createTextNode("empty"));
                        }
                        row.appendChild(cell);

                    }
                    table.append(row);

                }


                $("#dvCSV").html('');
                $("#dvCSV").append(table);
            }

});

我没有测试过这段代码。

【讨论】:

    猜你喜欢
    • 2013-05-18
    • 2018-12-09
    • 2018-01-03
    • 2013-05-21
    • 1970-01-01
    • 2013-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多