Ich habe den folgenden HTML-Code:
<input type='file' multiple>
Und hier ist mein JS-Code:
var inputFiles = document.getElementsByTagName("input")[0];
inputFiles.onchange = function(){
var fr = new FileReader();
for(var i = 0; i < inputFiles.files.length; i++){
fr.onload = function(){
console.log(i) // Prints "0, 3, 2, 1" in case of 4 chosen files
}
}
fr.readAsDataURL(inputFiles.files[i]);
}
Meine Frage ist also wie kann ich diese Schleife synchron machen? Das ist das Warten, bis die Datei vollständig geladen ist, und dann zur nächsten Datei übergehen. Jemand sagte mir, JS Promises
zu verwenden. Aber ich kann es nicht schaffen zu arbeiten. Folgendes versuche ich:
var inputFiles = document.getElementsByTagName("input")[0];
inputFiles.onchange = function(){
for(var i = 0; i < inputFiles.files.length; i++){
var fr = new FileReader();
var test = new Promise(function(resolve, reject){
console.log(i) // Prints 0, 1, 2, 3 just as expected
resolve(fr.readAsDataURL(inputFiles.files[i]));
});
test.then(function(){
fr.onload = function(){
console.log(i); // Prints only 3
}
});
};
}
Danke im Voraus...
Wenn Sie dies mit Promises nacheinander (nicht synchron) durchführen möchten, können Sie Folgendes tun:
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);
});
}
Wir haben die Antwort von midos geändert, um Folgendes zu erreichen:
function readFile(file){
return new Promise((resolve, reject) => {
var fr = new FileReader();
fr.onload = () => {
resolve(fr.result )
};
fr.readAsText(file.blob);
});
}
Das Wesen von FileReader
ist, dass Sie nicht synchron arbeiten können.
Ich vermute, Sie brauchen oder möchten nicht, dass es synchron ist, nur dass Sie die resultierenden URLs korrekt erhalten möchten. Wenn ja, würde ich nicht glauben, dass Versprechen wirklich helfen würden. Behalten Sie stattdessen die Anzahl der ausstehenden Vorgänge im Auge, damit Sie wissen, wann Sie fertig sind:
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;
});
}
Oder wenn Sie aus irgendeinem Grund die Dateien sequentiell lesen möchten (aber immer noch asynchron), können Sie dies tun, indem Sie den nächsten Aufruf nur planen, wenn der vorherige abgeschlossen ist:
// 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);
}
}
Ich aktualisiere Jens Lincke antwortete durch Hinzufügen eines funktionierenden Beispiels und führe die asynchrone/Warte-Syntax ein
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>
Hier ist eine weitere Änderung an Jens 'Antwort (Huckepack auf Midos Antwort), um zusätzlich die Dateigröße zu überprüfen:
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.onloadend = () => {
data = fr.result;
resolve(data)
};
fr.readAsDataURL(file);
}
});
}