8

我正在尝试加载一个行数约为 100k 的文件,到目前为止浏览器一直在崩溃(本地)。我在互联网上查看,发现 Papa Parse 似乎可以处理大文件。现在加载到 textarea 的时间减少到大约 3-4 分钟。加载文件后,我想再做一些 jQuery 来做计数和事情,所以这个过程需要一段时间。有没有办法让 csv 加载更快?我是否正确使用该程序?

<div id="tabs">
<ul>
  <li><a href="#tabs-4">Generate a Report</a></li>
</ul>
<div id="tabs-4">
  <h2>Generating a CSV report</h2>
  <h4>Input Data:</h4>      
  <input id="myFile" type="file" name="files" value="Load File" />
  <button onclick="loadFileAsText()">Load Selected File</button>
  <form action="./" method="post">
  <textarea id="input3" style="height:150px;"></textarea>

  <input id="run3" type="button" value="Run" />
  <input id="runSplit" type="button" value="Run Split" />
  <input id="downloadLink" type="button" value="Download" />
  </form>
</div>
</div>

$(function () {
    $("#tabs").tabs();
});

var data = $('#input3').val();

function handleFileSelect(evt) {
    var file = evt.target.files[0];

Papa.parse(file, {
    header: true,
    dynamicTyping: true,
    complete: function (results) {
        data = results;
    }
});
}

$(document).ready(function () {

    $('#myFile').change(function(handleFileSelect){

    });
});


function loadFileAsText() {
    var fileToLoad = document.getElementById("myFile").files[0];

    var fileReader = new FileReader();
    fileReader.onload = function (fileLoadedEvent) {
        var textFromFileLoaded = fileLoadedEvent.target.result;
        document.getElementById("input3").value = textFromFileLoaded;
    };
    fileReader.readAsText(fileToLoad, "UTF-8");
}
4

2 回答 2

11

您可能使用正确,只是程序需要一些时间来解析所有 100k 行!

这对于Web Workers来说可能是一个很好的用例场景。

注意:根据下面@tomBryer 的回答,Papa Parse 现在支持开箱即用的 Web Worker 。这可能是比滚动自己的工人更好的方法。

如果您以前从未使用过它们,这个网站提供了一个不错的概要,但关键部分是:

Web Workers 模仿多线程,允许在后台运行密集的脚本,因此它们不会阻止其他脚本的运行。非常适合保持您的 UI 响应,同时还执行处理器密集型功能。

浏览器覆盖率也相当不错,IE10 及以下版本是唯一不支持它的半现代浏览器。

Mozilla 有一个很好的视频,展示了网络工作者如何加快页面的帧速率。

我将尝试为您提供一个使用 web 工作者的工作示例,但还要注意这不会加快脚本的速度,它只会使其异步处理,以便您的页面保持响应。

编辑

注意:如果您想在工作线程中解析 CSV,您可能需要使用importScript函数(在工作线程中全局定义)在 worker.js 中导入 Papa Parser 脚本。有关更多信息,请参阅MDN 页面在那。)

这是我的工作示例:

csv.html

<!doctype html>
<html>
<head>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/4.1.2/papaparse.js"></script>
</head>

<body>
  <input id="myFile" type="file" name="files" value="Load File" />
  <br>
  <button class="load-file">Load and Parse Selected CSV File</button>
  <div id="report"></div>

<script>
// initialize our parsed_csv to be used wherever we want
var parsed_csv;
var start_time, end_time;

// document.ready
$(function() {

  $('.load-file').on('click', function(e) {
    start_time = performance.now();
    $('#report').text('Processing...');

    console.log('initialize worker');

    var worker = new Worker('worker.js');
    worker.addEventListener('message', function(ev) {
      console.log('received raw CSV, now parsing...');

      // Parse our CSV raw text
      Papa.parse(ev.data, {
        header: true,
        dynamicTyping: true,
        complete: function (results) {
            // Save result in a globally accessible var
          parsed_csv = results;
          console.log('parsed CSV!');
          console.log(parsed_csv);

          $('#report').text(parsed_csv.data.length + ' rows processed');
          end_time = performance.now();
          console.log('Took ' + (end_time - start_time) + " milliseconds to load and process the CSV file.")
        }
      });

      // Terminate our worker
      worker.terminate();
    }, false);

    // Submit our file to load
    var file_to_load = document.getElementById("myFile").files[0];

    console.log('call our worker');
    worker.postMessage({file: file_to_load});
  });

});
</script>
</body>

</html>

worker.js

self.addEventListener('message', function(e) {
    console.log('worker is running');

    var file = e.data.file;
    var reader = new FileReader();

    reader.onload = function (fileLoadedEvent) {
        console.log('file loaded, posting back from worker');

        var textFromFileLoaded = fileLoadedEvent.target.result;

        // Post our text file back from the worker
        self.postMessage(textFromFileLoaded);
    };

    // Actually load the text file
    reader.readAsText(file, "UTF-8");
}, false);

它处理的 GIF,不到一秒钟(全部在本地运行)

工作示例的 GIF

于 2016-06-29T13:13:59.453 回答
6

从 v5 开始,PapaParse 现已融入WebWorkers

下面是在 Papaparse 中调用 worker 的简单示例

Papa.parse(bigFile, {
    worker: true,
    step: function(results) {
        console.log("Row:", results.data);
    }
});

如果您有自己的 PP 工作者,则无需重新实现,但对于未来的项目,有些人可能会发现使用 PapaParse 的解决方案更容易。

于 2019-06-01T16:21:10.143 回答