Javascript Promises with FileReader()

半腔热情 提交于 2019-11-28 06:59:26

If you want to do it sequentially( not synchronously) using Promises, you could do something like:

var inputFiles = document.getElementsByTagName("input")[0];
inputFiles.onchange = function(){
  var promise = Promise.resolve();
  inputFiles.files.map( file => promise.then(()=> pFileReader(file)));
  promise.then(() => console.log('all done...'));
}

function pFileReader(file){
  return new Promise((resolve, reject) => {
    var fr = new FileReader();  
    fr.onload = resolve;  // CHANGE to whatever function you want which would eventually call resolve
    fr.readAsDataURL(file);
  });
}
Jens Lincke

We modified midos answer to get it to work the following:

function readFile(file){
  return new Promise((resolve, reject) => {
    var fr = new FileReader();  
    fr.onload = () => {
      resolve(fr.result )
    };
    fr.readAsText(file.blob);
  });
}

The nature of FileReader is that you cannot make its operation synchronous.

I suspect you don't really need or want it to be synchronous, just that you want to get the resulting URLs correctly. If so, I wouldn't think promises would really help. Instead, just keep track of how many outstanding operations you have so you know when you're done:

var inputFiles = document.getElementsByTagName("input")[0];
inputFiles.onchange = function(){
    var data = [];      // The results
    var pending = 0;    // How many outstanding operations we have

    // Schedule reading all the files (this finishes before the first onload
    // callback is allowed to be executed)
    Array.prototype.forEach.call(inputFiles.files, function(file, index) {
        // Read this file, remember it in `data` using the same index
        // as the file entry
        var fr = new FileReader();
        fr.onload = function() {
            data[index] = fr.result;
            --pending;
            if (pending == 0) {
                // All requests are complete, you're done
            }
        }
        fr.readAsDataURL(file);
        ++pending;
    });
}

Or if you want for some reason to read the files sequentially (but still asynchronously), you can do that by scheduling the next call only when the previous one is complete:

// Note: This assumes there is at least one file, if that
// assumption isn't valid, you'll need to add an up-front check
var inputFiles = document.getElementsByTagName("input")[0];
inputFiles.onchange = function(){
    var index = 0;

    readNext();

    function readNext() {
        var file = inputFiles.files[index++];
        var fr = new FileReader();
        fr.onload = function() {
            // use fr.result here
            if (index < inputFiles.files.length) {
                // More to do, start loading the next one
                readNext();
            }
        }
        fr.readAsDataURL(file);
    }
}

I upgrade Jens Lincke answer by add working example and introduce async/await syntax

function readFile(file) {
  return new Promise((resolve, reject) => {
    let fr = new FileReader();
    fr.onload = x=> resolve(fr.result);
    fr.readAsDataURL(file) // or readAsText(file) to get raw content
})}

function readFile(file) {
  return new Promise((resolve, reject) => {
    let fr = new FileReader();
    fr.onload = x=> resolve(fr.result);
    fr.readAsDataURL(file) // or readAsText(file) to get raw content
})}

async function load(e) {
  for(let [i,f] of [...e.target.files].entries() ){
    msg.innerHTML += `<h1>File ${i}: ${f.name}</h1>`;
    let p = document.createElement("pre");
    p.innerText += await readFile(f);
    msg.appendChild(p);
  }
}
<input type="file" onchange="load(event)" multiple />
<div id="msg"></div>

Here is another modification to Jens' answer (piggybacking off Mido's answer) to additionally check the file size:

function readFileBase64(file, max_size){
        max_size_bytes = max_size * 1048576;
        return new Promise((resolve, reject) => {
            if (file.size > max_size_bytes) {
                console.log("file is too big at " + (file.size / 1048576) + "MB");
                reject("file exceeds max size of " + max_size + "MB");
            }
            else {
            var fr = new FileReader();  
            fr.onload = () => {
                data = fr.result;
                resolve(data)
            };
            fr.readAsDataURL(file);
            }
        });
    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!