简体   繁体   English

JavaScript:如何在同步代码中使用异步FileReader?

[英]JavaScript: how to use async FileReader in sync code?

I have following code that works syncronously. 我有以下代码可以同步工作。 Basically it accept html form and parse it's elements into url string. 基本上,它接受html格式并将其元素解析为url字符串。

SmFaq.DataForm = function (f) { // f is HTML form
    var P = new Array();

    /* parsing array */

    var params = P.join("&");
    return params;
}

It worked nice, but now i need to add input type="file" . 它工作得很好,但是现在我需要添加input type="file" I made request based on this article: Sending forms with JavaScript ( Dealing with binary data ) and everything works fine except loading binary data in request body. 我根据本文提出了请求: 使用JavaScript发送表单处理二进制数据 ),除了将二进制数据加载到请求正文中之外,其他一切工作正常。 My function return string before file was readed. 我的函数在读取文件之前返回字符串。

Task: i need to read and add binary data to request body string and then return this string. 任务:我需要读取二进制数据并将其添加到请求正文字符串中,然后返回此字符串。 Is it possible? 可能吗? I don't care if GUI will freeze for loading time. 我不在乎GUI是否会因加载时间而冻结。

Here's my code: 这是我的代码:

SmFaq.DataForm = function (f) { 

    var name = f.querySelector('#created_by'); 
    var email = f.querySelector('#created_by_email'); 
    var question = f.querySelector('#question'); 
    var file = { 
        dom: f.querySelector('#file'), 
        binary: null 
    }; 

    var reader = new FileReader(); // to read binary data 


    if (file.dom.files[0]) { 
        reader.readAsBinaryString(file.dom.files[0]); 
    } 

    file.dom.addEventListener('change', function() { 
    if (reader.readyState === FileReader.LOADING) { 
        reader.abort(); 
    } 

        reader.readAsBinaryString(file.dom.files[0]); 
    }); 

    reader.addEventListener('loadend', function() { 
        file.binary = reader.result; 
        console.log('Binary data loaded!'); 
    }); 

    return sendData(); 

    function sendData() { 

        if (!file.binary && file.dom.files.length > 0) { 
            setTimeout(sendData, 2000); 
            return; 
        } 


        var boundary = "1234567890"; 

        var data = ''; 

        data += '--' + boundary + '\r\n'; 
        data += 'content-disposition: form-data; ' 
        + 'name="' + file.dom.name + '";' 
        + 'filename="' + file.dom.files[0].name + '"\r\n'; 
        data += 'Content-Type: ' + file.dom.files[0].type + '\r\n'; 
        data += '\r\n';
        data += file.binary + '\r\n';

        data += '--' + boundary + '\r\n'; 
        data += 'content-disposition: form-data; name="' + name.name + '"\r\n'; 
        data += '\r\n'; 
        data += name.value + '\r\n'; 

        data += '--' + boundary + '\r\n';
        data += 'content-disposition: form-data; name="' + email.name + '"\r\n'; 
        data += '\r\n'; 
        data += email.value + '\r\n'; 

        data += '--' + boundary + '\r\n';
        data += 'content-disposition: form-data; name="' + question.name + '"\r\n'; 
        data += '\r\n'; 
        data += question.value + '\r\n'; 
        data += '--' + boundary + '--'; 
        data += '\r\n'; 

        return data; 
    }
}

I do not know this async things so it sure not working as expected. 我不知道这种异步的事情,所以它肯定不能按预期工作。

Plese do not use ES7 features, i work with legacy code and have no possibility to use Babel. Plese不使用ES7功能,我使用的是旧版代码,因此无法使用Babel。

I don't think it is possible to do it synchronously. 我认为不可能同步进行。 Here is how to do it asynchronously : 这是异步执行的方法:

 var SmFaq = {}; SmFaq.DataForm = function(f, callback) { var name = f.querySelector('#created_by'), file = f.querySelector('#file'), data = '', reader = new FileReader(); reader.addEventListener('loadend', function() { console.log('Here are binary datas !'); data += reader.result; callback(data); }); data += 'Created by '; data += name.value; data += '\\n'; if (file.files[0]) { data += file.files[0].name; data += '\\n'; data += ' ... '; data += '\\n'; console.log('Waiting for binary datas...'); reader.readAsBinaryString(file.files[0]); } else { callback(data); } } function handleData(data) { // Do whatever you want to do with data console.log(data); } document.getElementById('myForm').addEventListener('submit', function(e) { e.preventDefault(); SmFaq.DataForm(this, handleData); }); 
 <form id="myForm"> <input type="text" id="created_by" placeholder="Who Am I ?" /><br /> <input type="file" id="file" /><br /> <input type="submit" value="Submit" /> </form> 

Change the way DataForm is called to add a callback to it, and call the callback function when you have all your datas. 更改调用DataForm的方式以向其添加回调,并在拥有所有数据时调用callback函数。 Then you handle those datas inside the callback function, handleData in my example. 然后,在回调函数(在我的示例中为handleData中处理这些数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM