解析大型csv文件时Jquery崩溃

时间:2015-03-09 09:24:54

标签: javascript jquery csv

我有一个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);
                }

    });

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

2 个答案:

答案 0 :(得分:4)

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

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包含此输入: <input type="file" id="fUpload" />

我如何配置爸爸:

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

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

  • chunk:代替每个已解析行的回调,有一个用于更大的行集。这更快;

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

您可以运行here

我使用包含的9.4 MB CSV文件进行了测试 1,Foo,100在每一行重复。

Here's the same but using a table输出数据并添加-1到VirtualList&#39; totalRows以补偿实际长度。

答案 1 :(得分:0)

我建议你使用console.log('...')来识别锁定/中断的位置,可能在第一个变量(rows,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);
            }

});

我没有测试过这段代码。