I am using ionic 3 platform for uploading a video file to vimeo api. I need to get binary data for video file and I am uploading using input type file element.
The code I have written is as follow
videoUploadBody(videoObj) {
const r = new FileReader();
r.onload = function(){
console.log("Binary data", r.result);
return r.result;
};
r.readAsArrayBuffer(videoObj);
}
This is the function that I need to call and it should return me video file in binary form. The function from where I am calling above function is as follow
uploadVideo(videoFile, createdVideo) : Observable<any> {
const bodyObj = this.compilerProvider.videoUploadBody(videoFile);
return this.http.patch<Observable<any>>(createdVideo.upload.upload_link, bodyObj, this.uploadReqOpts);
}
Here the bodyObj variable contains undefined, whereas I have console.log is videoUploadBody function gives me data in binary form.
I think there is some async or promise issue. What do I need to change to get back binary data in uploadVideo function?
You're correct in that it is a promise issue. In your first function, r.onload will only return after the first function returns, and even then it will only return from the nested function.
I'm not going to write the correct code for you, but what you have to do is wrap the first function's body in a promise that resolves within the r.onload function, then the second function should call .then on that promise to operate on it (hint: you'll need to make another promise here).
MDN has good information about Promise.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Related
Is it possible to convert a Blob to Uint8Array without using a callback and just using JavaScript?
How to return the uint8array for the calling variable uint8data?
let str='content';
str2blob=(str,type='text/plain')=>new Blob([str],{type:type});
let blob=str2blob(str);
function blob2uint(blob){
new Response(blob).arrayBuffer().then(buffer=>{
uint=[...new Uint8Array(buffer)];
console.log("Uint8Array",uint);
return uint;
});
}
let uint8data=blob2uint(blob);
console.log(uint8data); //Show Uint8Array
Assuming this is somewhere inside a function, you can make it async and use await to wait for the Promise to complete once you return it from the blob2uint function:
async function myBlobToUIntDemo() {
let str='content';
str2blob=(str,type='text/plain')=>new Blob([str],{type:type});
let blob=str2blob(str);
function blob2uint(blob){
return new Response(blob).arrayBuffer().then(buffer=>{
uint=[...new Uint8Array(buffer)];
console.log("Uint8Array",uint);
return uint;
});
}
let uint8data = await blob2uint(blob);
console.log(uint8data); //Show Uint8Array
}
Let's spike this up with some more information:
Why do I need a callback in the first place?
Because you are doing asynchronous work by pulling the arrayBuffer from a response. JavaScript (as far as I know) only runs in a single thread. Waiting for a website in your code without using a callback would halt all other JavaScript execution on your page if you didn't put it in the background somehow; that's what callbacks and Promises do for you (from the outside at least).
Promises?
Functions doing asynchronous work typically return a Promise object, that promises to provide you with the value once the work completes (by calling the function passed in the then callback with it) or an error in case something goes wrong (by calling the catch callback with it).
async / await
async / await was introduced to make working with Promises a bit nicer and readable, reducing the need for callbacks a lot. You can read more about that in this MDN article.
The code block above only contains the bare minimum changes to get things working. Let's simplify that a bit more!
async function myBlobToUIntDemo() {
let str = 'content';
let str2blob = (str, type = 'text/plain') => new Blob([str], { type: type });
let blob = str2blob(str);
const buffer = await new Response(blob).arrayBuffer();
const uint = [...new Uint8Array(buffer)];
console.log(uint);
}
Note that this returns a Promise as well (this automatically happens if you mark your function as async) so make sure to remember that if you were to use this function anywhere in your code.
I have written a library function pRead(Path), which returns a JavaScript Promise to read a file on the local computer under an Apache server, using Ajax. I won't include the code for this, as it uses standard technology that is well-known to anyone who can give a good answer to this question.
I want to write a second library function, pReadObj(Path), which will return a Promise to read a JSON file and provide its object value to asynchronous code. It should work like this:
pReadObj("test.json").then(then2).catch(pErr);
function then2(obj)
{
alert(JSON.stringify(obj)); // Shows the JSON obj
} // then2
Here is the code I wrote:
var globalPreviousResolve;
function pReadObj(Path) // Promise to read JSON from file
{
return new Promise(function(resolve,reject)
{
globalPreviousResolve=resolve;
pRead(Path).then(pReadObj2).catch(pErr);
});
} // pReadObj
function pReadObj2(JSONStr)
{
globalPreviousResolve(JSON.parse(JSONStr));
} // pReadObj2
function pTestDB() // Called from button
{
pReadObj("test.json").then(then2).catch(pErr);
} // pTestDB
This works, but has a problem: using a global variable to hold the resolve callback is not only ugly, but it will clearly malfunction if two calls to pReadObj happen within a short period of time and the disk read takes a longer time than that.
The resolve function needs to be stored inside the Promise in some way, I'm thinking.
There's no need to explicitly create a Promise; just return the one created by .then:
function pReadObj(Path) {
return pRead(Path).then(JSON.parse);
}
I want a script file just for accessing a JSON from a url. I want to have a method to return the JSON object from the script into a var in a separate script file then modify it accordingly. Obviously since javascript is asynchronous it fails if I simply write it out. Therefore I must use a promise:
var promise1 = new Promise(function(resolve, reject) {
access(userSearchText); //send user input to get appropriate JSON object
});
promise1.then(function(value) {
var getData = returnData(); //method that returns JSON object from the other script
alert(getData); //print out the returned JSON object
console.log("we have finished");
});
But this is not printing out anything. The alert does not occur at all and nothing is being printed in the console. I am using jquery to access the url in the other script and I have a .done after accessing it in the script for retrieving the JSON as: access.js
var sendData;
(function() {
jqxhr = $.getJSON( url, {
})
.done(function( data ) {
sendData = data;
});
})();
function returnData(){
return sendData;
}
So there should not be any asynchronous issues in the script for accessing the URL because of .done. I really don't understand why this isn't working. I inspected my page and there are no errors to be seen anywhere. Can anyone help?
promise1 never gets resolved.
In your definition of promise1, you never call the resolve() function to resolve it. Thus, it's .then() never gets called.
Manually created promises are only resolved when you explicitly call resolve() in the executor function.
If access() is itself asynchronous, then we will need to more about that function to help you do this correct. Wrapping a promise around it does not do anything to help you. If access() itself returns a promise, you should just use that promise and not wrap one around it.
Probably access() should return a promise that is resolved when it's asynchronous operation is done and then you can do:
access().then(...).catch(...);
And, not wrap it with another promise.
The sendData and returnData() stuff just looks wrong. You'd have to explain and show more context to know what exactly the recommend.
I have a asynchronous function (a promise), which reads an xml file and give a map of keys and value, if the promise is resolved. I need this map throughout my project. So i want to read this xml file only once, probably at the start of my project and save the map in a variable. And i want to use the variable in different files of my project. Is there any way by which i can achieve this?
You can define the functions in files to expect a parameter, use Promise.all() to load the files, pass the function reference from requested files to .then() within .then() chained to Promise.all()
const promise = Promise.resolve("do stuff");
promise.then(res => {
Promise.all([fetch("loadFile1.js").then(res => res.text())
/* , fetch("loadFile2.js")*/])
.then(function(files) {
let script = document.createElement("script");
script.textContent = files[0];
document.body.appendChild(script);
promise.then(loadFile)
})
});
where loadFiles1.js contains a function loadFile
function loadFile(data) {
console.log(data);
}
plnkr http://plnkr.co/edit/SQzakbP936rEgnEzsP8R?p=preview
I want get a image from my local harddrive. My function returns undefined.
function getImageFromLocal() {
var imageurl = 0;
return new WinJS.Promise(function () {
picturesLib.getItemAsync("APP Folder X").then(function (appfolder) {
appfolder.getItemAsync("Subfolder X").then(function (file) {
file.getItemAsync("Image.jpg").done(function (image) {
imageurl = URL.createObjectURL(image);
});
});
});
});
return imageurl;
}
When working with asynchronous API calls like StorageFolder.getItemAsync, it doesn't work to assign the ultimate result to a local variable and attempt to return that.
In your code, moreover, you have two return statements, the first of which returns a promise inside which is wrapped the return value from a chain of promises ending in .done, which is what's giving you undefined. The second return statement is never reached, and even if it were, would return the initial value of 0 because by that time the async code won't have executed.
I'll point out further that using new WinJS.Promise isn't at all what you want here, but I won't belabor the details. If you really want the full story on promises and how they work, refer to my free ebook, Programming Windows Store Apps with HTML, CSS, and JavaScript, Second Edition, both in Chapter 3 (basics) and Appendix A (full story).
Back to your code, I'm not entirely sure what you're trying to do. With your function named with "Local" you suggest you're trying to retrieve an image from your app data, but the use of a variable called picturesLib suggests you're coming from the Pictures library. Let me address each of those separately.
First, if you're working with local appdata, you can bypass the entire process you've shown here by simply using a URI in the form ms-appdata:///local/folder1/folder2/image.jpg. You can assign such a URI directly to an img.src attribute and it'll just work. This will work synchronously, and also works for ms-appx:/// URIs that refer to in-package resources.
Second, when working with images you cannot reference so conveniently with a URI, you need to get its StorageFile and pass that to URL.createObjectURL, the result of which you can assign to an img.src as well, as I think you know. To save some trouble, though, you can use a full relative path with StorageFile.getFileAsync. This way you avoid having to write a promise chain to navigate a folder structure and reduce all that to a single call. That is, if pictureLib is the StorageFolder from Windows.Storage.KnownFolders.picturesLibrary, then you can just use:
picturesLib.getFileAsync("App folder X\subfolder x\image.jpg");
Now for your original function, whose purpose is to return a URI for that image, it's necessary that it returns a promise itself, and that the caller attached a .done to that promise to obtain the result. You do this properly by returning the value you want inside the completed handler for getFileAsync, but be sure to use .then which returns a promise for that return value (.done will return undefined).
function getPicturesLibUriAsync(relativePath) {
return picturesLib.getFileAsync(relativePath).then(function (file) {
return URL.createObjectURL(file);
});
}
Then you call the method like this, using .done to get the async result:
getPicturesLibUriAsync("folder1\folder2\image1.jpg").done(function (uri) {
someImageElement.src = uri;
});
Again, refer to my book for full details on how promises work, especially using the return value of .then.