This function read files gotten from an input field and return their dataUrls:
readAsDataURL (target) {
// target => <input type="file" id="file">
var reader = new FileReader()
return new Promise(function (resolve, reject) {
reader.onload = function (event) {
resolve(event.target.result)
}
reader.readAsDataURL(target.files[0])
})
},
As you can see, the function only deals with single files. I want to return multiple files. I tried doing reader.readAsDataURL(target.files)
but got this error: 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'.
How to make the function return multiple dataUrls?
This function read files gotten from an input field and return their dataUrls:
readAsDataURL (target) {
// target => <input type="file" id="file">
var reader = new FileReader()
return new Promise(function (resolve, reject) {
reader.onload = function (event) {
resolve(event.target.result)
}
reader.readAsDataURL(target.files[0])
})
},
As you can see, the function only deals with single files. I want to return multiple files. I tried doing reader.readAsDataURL(target.files)
but got this error: 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'.
How to make the function return multiple dataUrls?
Share Improve this question asked Jun 13, 2017 at 2:44 alexalex 7,61115 gold badges53 silver badges80 bronze badges 2-
Just a note, if you are trying to display multiple media files into the doc, through e.g
<img>
or<video>
, then don't even go theFileReader
way :URL.createObjectURL()
is synchronous, takes no time, no memory, and should always be preferred to heavy dataURIs – Kaiido Commented Jun 13, 2017 at 3:10 - @Kaiido Oh, I didn't know about this. Could you write an answer with a sample code please? – alex Commented Jun 13, 2017 at 3:12
2 Answers
Reset to default 3Have you tried using Promise.all? You might be able to do something like:
fileToDataURL(file) {
var reader = new FileReader()
return new Promise(function (resolve, reject) {
reader.onload = function (event) {
resolve(event.target.result)
}
reader.readAsDataURL(file)
})
}
readAsDataURL (target) {
// target => <input type="file" id="file">
var filesArray = Array.prototype.slice.call(target.files)
return Promise.all(filesArray.map(fileToDataURL))
}
This essentially does the same thing you had setup, but creates a promise for each one, returning the result in an array only once all have been pleted.
I forgot that you cannot treat target.files
directly as an array, so it needs to be converted first. For this you can use: Array.prototype.slice.call(target.files)
It's not clear from the question what you'll do with these dataURIs, but most of the time, you don't actually need it.
To be able to display a media from a user's File, or from a Blob, into your document, it is better to use the URL.createObjectURL()
method which will return a blobURI, that you can use like any url.
Non exhaustive list of blobURIs advantages :
- is synchronous. You don't need your Promise wrapping event handlers hell, all can be done in a single loop.
- is fast. The browser doesn't read the File or Blob passed, it just creates a symlink in the memory to the real File in the HDD.
- is memory light-weight. Because of previous point. When pared to
readAsDataURL()
, you should note that this latter will first read the file entirely, convert it to a base64 string (~34% bigger than original data), and finally, you will store this big string in the DOM's markup, making it always present in memory. From then, the browser will read it again, convert it to binary, read it again as binary and finally process it as an normal resource.
"But I need to send it to the server !"
Then send the File directly, as multipart data. Less work on the front-side, less work in the pipes (remember ~34%), and less work server-side if you wanted to save a File there.
Most server-side languages have easy built-ins methods to catch Files from POST requests, and you can send it easily from the front with the FormData
API.
Here is an example of your code, using blobURIs, which excpects all Files are images.
document.querySelector('input').onchange = function(){
// FileList doesn't have an forEach method yet
Array.prototype.forEach.call(this.files, function(file){
if(file.type.indexOf('image/' === 0)){
var i = new Image();
i.src = URL.createObjectURL(file); // creates a blobURI
document.body.appendChild(i);
}
});
};
<input type="file" multiple>
But note that this method can also have cons :
- Don't use it with MediaStreams. It will lock the source of the MediaStream until the blobURI is revoked (either when
URL.revokeObject(blobURI)
is called, or on an hard refresh of the page. In this case, you should usemediaElement.srcObject = MediaStream;
instead. For Blobs you created, (not ing from an
<input>
), the same point applies : the blob will be stuck in memory until expressly released. In this case, simply callURL.revokeObjectURL(blobURI)
once the resource is loaded.img.onload = URL.revokeObjectURL(img.src); img.src = URL.createObjectURL(the_Blob_I_built);
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745147004a4613691.html
评论列表(0条)