【问题标题】:Controlling Load Order when Reading File Lines读取文件行时控制加载顺序
【发布时间】:2019-11-01 22:48:31
【问题描述】:

TLDR:如何打开文件(流式 txt)(最好是异步的,因为文件可能很大)并按顺序显示它们?

我有一个允许用户打开多个文件的页面。读取每个文件行,然后将push 添加到display 变量的数组中。然后显示数组显示为:

document.getElementById('content').innerHTML = <table id ="mainView">' + display.join('') + '</table>';.

这很好用,但是由于文件是异步加载的,因此文件行被无序推送到数组中。有没有办法设计一种使用异步文件加载但保留文件顺序的机制?最后,有没有办法在没有库/框架的情况下在 javascript 中做到这一点?

文件顺序由升序的数字命名约定决定。

log12 <- lines in this log should appear first in the table
log16
log48
log103

电流输出

log48 content
log12 content
log48 content
log103 content

预期输出

log12 content
log16 content
log48 content
log103 content

这里是我如何加载多个文件、逐行读取它们、附加到数组并在页面上显示它们的要点。

文件上传表单调用该函数:

function handleFileSelect(evt) {
    var files = evt.target.files;
    fileArray = [].slice.call(files);
    for (var i = 0; i < fileArray.length; i++) { 
        console.log(fileArray[i].name);
        getContents(fileArray[i]);
    }
}

加载和显示每个文件的行。我应该注意到display 是一个全局数组。

function getContents(f){
    if(f){
        var reader = new FileReader();
        reader.readAsText(f, "UTF-8");
        var fileIndexname = f.name
    }

     reader.onload = function(evt){
        var lines = evt.target.result;
        // do some file splitting with regex here (removed for simplicity)
        for(var i = 0; i < lines.length; i++){
            display.push('<tr><td>' + lines[i] + '</td></tr>');
        }
        document.getElementById('content').innerHTML = '<table id ="mainView">' + display.join('') + '</table>';
    }
}

【问题讨论】:

    标签: javascript file asynchronous


    【解决方案1】:

    我会依靠 Promise.all 来维护上传文件的顺序。
    在输入文件发生更改事件时,我将上传的文件映射到将读取每个文件的文件内容的 Promise。
    您可以看到我使用不同的 API 来读取文件内容,因为 Blob.text() 是首选的基于 Promise 的新 API。
    然后 Promise.all() 收集结果,保持上传文件的顺序,如果这是你想要的。

    如果您需要独立于上传顺序对所有文件中的所有行进行排序,请使用此 displayAllLinesSorted 函数。

    document.getElementById('upload').addEventListener('change', (event) => {
      const files = [].slice.call(event.target.files);
      const filePromises = files.map(file => {
        return file.text().then(result => {
        	return result.split(/[\r\n]+/g);
        });
      });
      Promise.all(filePromises).then(display);
    });
    
    function linesReducer(accumulator, currentValue) {
      return accumulator + `<tr><td>${currentValue}</td></tr>`;
    }
    
    function display(results) {
      const table = document.getElementById('table');
      table.innerHTML = results.flat().reduce(linesReducer, '');
    }
    
    function displayAllLinesSorted(results) {
      const table = document.getElementById('table');
      table.innerHTML = results.flat().sort().reduce(linesReducer, '');
    }
    <input type=file id=upload multiple />
    
    <table id=table></table>

    只是一个注释,因为你说过:

    最好异步,因为文件可能很大

    异步并不意味着你的性能在大文件上就可以了。特别是在这种情况下,您正在使用 FileReader.readAsText() 方法,它会一次加载整个文件内容。
    如果你真的想处理大文件,你应该使用 Blob.stream()Blob.slice() 并且你的 DOM &lt;table&gt; 应该一次只包含文件的一部分。您的 UI 应该允许用户在文件中来回移动。

    【讨论】:

    • 这非常有效。最后一个问题:promise 知道输入数组的顺序吗?那就是如果我在传递给Promise之前对文件数组进行了排序,它和之后排序的效果一样吗?
    • 如果您的意思是基于文件 namefiles 数组进行排序,然后映射到 Promises 以获取 filePromises,那么是的,它将保持该顺序。
    • 为了简化,如果你有['foo', 'bar', 'baz'].sort(...).map(...),你会得到[p('bar'), p('baz'), p('foo')],其中p() 代表一个Promise。 Promise.all 将为您提供一个结果数组,保持 Array in 参数的顺序(在我们的例子中为filePromises)。
    猜你喜欢
    • 1970-01-01
    • 2012-03-25
    • 1970-01-01
    • 1970-01-01
    • 2019-11-02
    • 2012-11-29
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    相关资源
    最近更新 更多