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

时间:2017-12-13 09:16:11

标签: javascript ajax asynchronous request multipartform-data

我有以下代码同步工作。基本上它接受html表单并将其元素解析为url字符串。

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

    /* parsing array */

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

它工作得很好,但现在我需要添加input type="file"。我根据这篇文章发出了请求:Sending forms with JavaScript处理二进制数据),除了在请求体中加载二进制数据外,一切正常。我的函数在文件被引用之前返回字符串。

任务:我需要读取并添加二进制数据以请求正文字符串,然后返回此字符串。可能吗?我不在乎GUI是否会冻结加载时间。

这是我的代码:

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; 
    }
}

我不知道这种异步的事情,所以它确实没有按预期工作。

请不要使用ES7功能,我使用遗留代码,不可能使用Babel。

1 个答案:

答案 0 :(得分:2)

我认为不可能同步进行。以下是异步执行的方法:

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>

更改调用DataForm的方式以向其添加回调,并在拥有所有数据时调用callback函数。然后在我的示例中处理回调函数handleData中的那些数据。