使用 JavaScript 读取多个文件并等待结果

Read Multiple Files With JavaScript and Wait for Result

首先我想说(来自 c++ 和 python)我是 JS 的新手,所以我欢迎对我的代码提出任何明智的建议。

我希望使用 HTML5 文件 API 读取一些文件,然后用 JS 打开它们,执行一些操作并下载压缩的结果。我的问题是读取文件似乎是一个异步操作,我真的没有看到一种优雅的方式来等待它们全部完成然后压缩结果。

此处提供了一种可能的解决方案: 但我想知道是否可以比使用全局标志做得更好。

我在从异步函数中检索结果时也遇到了问题,因为我不知道如何在 changeCharsInFiles 中返回 new_file_list

谢谢!

代码示例: HTML:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    </head>
    <body >
        <div class="container">
            <div class="jumbotron">
                <h3>Add Files Here</h3>
                <input type="file" id="the-file-field" multiple>
            </div>
        </div>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.5/jszip.min.js"></script>
        <script src="http://cdn.jsdelivr.net/g/filesaver.js"></script>
        <script>
         ########### SEE JS BELOW #####################
    </script>
</body>

JS:

if (window.File && window.FileReader && window.FileList && window.Blob) {

                //functions
                function zipMyFilesAndSave(file_list){

                    var zip = new JSZip();
                    for (var i = 0; i<file_list.length; i+=1)
                    {
                        zip.file(file_list[i].name, file_list[i]  );
                    }
                    zip.generateAsync({type:"blob"}).then(
                    function (blob) {                                      
                        saveAs(blob, "hello.zip");                         
                    }, 
                    function (err) {
                        jQuery("#blob").text(err);
                    }); 
                }

                function changeCharsInFiles(file_list){
                    var new_file_list = [];

                    for (var i = 0; i<file_list.length; i+=1)
                    {
                        var file = file_list[i]

                        var reader = new FileReader();
                        reader.onload = function() {
                            //alert(reader.result);
                            var txt  = reader.result;
                            console.log("txt: ",txt)

                            var new_txt = ""
                            var allTextLines = txt.split(/\r\n|\n/);

                            for (var j = 0; j<allTextLines.length; j+=1)
                            {
                                var res = allTextLines[j].replace("a", "A");
                                res = res.replace("b", "B");
                                res = res.replace("c", "C");
                                res = res.replace("d", "D");

                                new_txt += res + "\n"

                            }
                            console.log("new_txt: ", new_txt)
                            var new_file = new Blob([new_txt], {type: "text/plain"});

                            new_file_list.push(new_file); //<---------------------------how do I get this back?
                        }
                        reader.readAsText(file);    

                    }


                    return new_file_list;
                }

                //watcher
                $( "#the-file-field" ).change(function() {
                    console.log("files have been chosen")
                    var file_list = this.files
                    file_list = changeCharsInFiles(file_list)
                    zipMyFilesAndSave(file_list)    
                });


            } else {
                alert('The File APIs are not fully supported in this browser.');
            }

尝试阅读 Promise class,它是为了简化异步操作而开发的:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

在你的情况下,你可以这样使用它:

function changeCharsInFiles(file_list){
    let promises = [];
    for (let file of file_list) {
        let filePromise = new Promise(resolve => {
            let reader = new FileReader();
            reader.readAsText(file);
            reader.onload = () => resolve(reader.result);
        });
        promises.push(filePromise);
    }
    Promise.all(promises).then(fileContents => {
        // fileContents will be an array containing
        // the contents of the files, perform the
        // character replacements and other transformations
        // here as needed
    });
}

这只是解决方案的粗略概述。我建议您首先对 Promises 进行一些实验(它可能是一个相当深的主题)以找出基本原则,然后应用类似上述的内容。