Here is the code I'm working with (IP address censored for obvious reasons):
async function buildJobsView() {
let jobList = await getJobs()
Promise.all([getJobs()]).then($("#jobsPane").text(jobList))
}
async function getJobs() {
//Open API connection and submit
var url = "http://IPADDRESS:8082/api/jobs?IdOnly=true"
var xhr = new XMLHttpRequest()
xhr.open("GET", url, true)
xhr.send()
xhr.onreadystatechange = function() {
if(xhr.readyState == 4 && xhr.status == "200") {
return xhr.response
}
}
}
For whatever reason, the jobList variable is being assigned before the getJobs() function finishes running. The getJobs() function does return the right output eventually, but the code has already moved on. What am I doing wrong?
async doesn't automatically convert callback-based code into Promise-based code - you have to explicitly convert the callback to a Promise and return a Promise whenever you want to be able to use it as a Promise.
function getJobs() {
return new Promise((resolve) => {
//Open API connection and submit
var url = "http://IPADDRESS:8082/api/jobs?IdOnly=true"
var xhr = new XMLHttpRequest()
xhr.open("GET", url, true)
xhr.send()
xhr.onreadystatechange = function() {
if(xhr.readyState == 4 && xhr.status == "200") {
resolve(xhr.response)
}
}
});
}
Then, getJobs will return a Promise, and then you can consume it with await:
const jobList = await getJobs()
Related
I try to get content with an async call and grab the response via an async function. What is wrong with this setup? The result of the console log is always undefined?
_json: function (callback) {
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', this.options.url, true);
xobj.onreadystatechange = function () {
if (xobj.readyState == 4 && xobj.status == "200") {
callback(xobj.responseText);
}
};
xobj.send(null);
},
get: async function () {
var resp = await this._json(function(response) {
return JSON.parse(response);
});
console.log(resp);
}
In order to use async / await you need to know when to use await in the first place. You cannot just put simply await infront of anything and expect that it somehow awaits something.
So, when should you use await or lets say when does it make sense to use it?
One simple question:
Does your method / function returns an Promise?
Yes: You can put await infront of it
No: Its useless to use await
We can make that check on your issue:
Does this._json() returns an Promise?
In your case no. That means using await is useless.
What you can do is returning an promise:
_json: function () {
return new Promise((res, rej) => {
var xobj = new XMLHttpRequest()
xobj.overrideMimeType('application/json')
xobj.open('GET', this.options.url, true)
xobj.onreadystatechange = function () {
if (xobj.readyState == 4 && xobj.status === 200) {
res(xobj.responseText)
} else {
rej('Something went wrong')
}
}
xobj.send(null)
})
},
get: async function () {
var resp = await this._json()
console.log(resp)
},
this._json() returns an Promise now. In this case it makes sense to use await.
Remember: By putting async infront of an function,your function then returns also an promise.
Your _json function is not a Promise. It uses common callback pattern to pass information back asynchronously. You have to wrap it in a Promise first, if you want to use async/await syntax.
new Promise((resolve) => this._json((response) => resolve(JSON.parse(response)))
Then you can await it and receive parsed JSON (as you expect).
I have implemented an async function which creates an XHR object inside a Promise, requests a data from the server and fulfills the Promise with the response received from the server
async function playWordsAudio(id, type, check=false){
let file_namePromise = new Promise(function (onSuccess, onFailure){
var xhttp = new XMLHttpRequest();
xhttp.onload = function(){
if(this.readyState == 4 && this.status == 200){
if(this.responseText !== "No Data"){
file_name = this.responseText;
if(check == false){
audio = new Audio('assets/uploads/wav/' + file_name);
audio.play();
}else{
onSuccess(file_name);
}
}else{
if(check){
onSuccess('Not Found');
}
}
}
};
xhttp.open("GET", "scripts/get_word_audio.php?id=" + id + "&type=" + type, true);
xhttp.send();
});
let resultant = await file_namePromise;
if(check){
return resultant;
}
}
Later I have defined another function which calls the async function shown above
function modify_object(id, type, obj){
result = playWordsAudio(id, type, true);
result.then(function(value){
if(value == "Not Found"){
obj.classList.remove('fa-play');
}
});
}
Later in the implementation I also call the modify_object function and pass it an object for modification as described in the function.
modify_object(id, type, plays[i]);
In the async function I have created a Promise, on success I pass it the file_name received from the XHR response or else I pass it 'Not Found'.
Here I am confused on how the await part works inside the asyc function.
It returns the resultant to the caller of the async function which is
result = playWordsAudio(id, type, true);
If so, what does the onSuccess method in the Promise do
let file_namePromise = new Promise(function (onSuccess, onFailure){
/*
Some Codes
*/
onSuccess(file_name);
/*
Some more code
*/
onSuccess('Not Found);
/*
Rest of the Code
*/
}
As I have checked by commenting out the return statement after the await statement
if(check){
// return resultant;
}
The Promise is not fulfilled.
How does each part of the implementation work as described above?
I am using Async XMLHttpRequest to make an API call. Here's the workflow of my program,
first_function(){
var valueToBeReturned = 0;
makeRequest(myCallback)//function for API call
/*rest of the code*/
console.log("print second");
return valueToBeReturned;
}
function makeRequest(callback){
var xhttp = new XMLHttpRequest();
xhttp.open("GET", "my_url", true);
xhttp.send(null);
xhttp.onload = function() {
if(xhttp.readyState === 4) {
if(xhttp.status === 200) {
response = JSON.parse(xhttp.responseText);
callback(null, response);
}
}
}
}
function myCallback(data){
console.log("print first")
}
Now what happens is every time I run it, the entire code in the first function is executed and then the code in makeRequest is executed. I understand JS is synchronous in nature and everything. But I'm not able to get my work done here, which is fisrt it makes API call, then callback is executed, then the code after makeRequest. What am I doing wrong here?
PS this is not the actual code, just to demonstrate the flow of my program
You need to put callback as a parameter in makeRequest. I'm not sure what that null is there for, though. If you want "print second" to print second, you'll need to execute it after myCallback - maybe insert another callback?
function first_function(){
var valueToBeReturned = 0;
makeRequest(myCallback, restOfTheCode)
function restOfTheCode() {
/*rest of the code*/
console.log("print second");
}
}
function makeRequest(callback1, callback2){
var xhttp = new XMLHttpRequest();
xhttp.open("GET", "my_url", true);
xhttp.send(null);
xhttp.onload = function() {
if(xhttp.readyState === 4 && xhttp.status === 200) {
const response = JSON.parse(xhttp.responseText);
callback1(response);
callback2(response);
}
}
}
function myCallback(data){
console.log("print first");
}
But this whole thing would be a whole lot nicer if you used Fetch and Promises instead:
function makeRequest() {
return fetch('my_url')
.then(response => response.JSON())
}
// consume the request:
makeRequest()
.then(responseJSON => {
// do stuff with the responseJSON
});
I'm writing webpage with a javascript to read data files in text format from the server per user request. Once the text file has been loaded, I need to manipulate the data somewhat.
I have been using XMLHttpRequest for the loading, however, now I see that synchronous requests are "deprecated". I can't start manipulating the data before it's loaded, so what can I do in this case?
Use an asynchronous request (or fetch, see below, which is also asynchronous):
function doGET(path, callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
// The request is done; did it work?
if (xhr.status == 200) {
// ***Yes, use `xhr.responseText` here***
callback(xhr.responseText);
} else {
// ***No, tell the callback the call failed***
callback(null);
}
}
};
xhr.open("GET", path);
xhr.send();
}
function handleFileData(fileData) {
if (!fileData) {
// Show error
return;
}
// Use the file data
}
// Do the request
doGET("/path/to/file", handleFileData);
Or using promises, which are the more modern way to handle callbacks (but keep reading):
function doGET(path, callback) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
// The request is done; did it work?
if (xhr.status == 200) {
// Yes, use `xhr.responseText` to resolve the promise
resolve(xhr.responseText);
} else {
// No, reject the promise
reject(xhr);
}
}
};
xhr.open("GET", path);
xhr.send();
});
}
// Do the request
doGET("/path/to/file")
.then(function(fileData) {
// Use the file data
})
.catch(function(xhr) {
// The call failed, look at `xhr` for details
});
Here in 2019, there's no reason to use XHR wrapped in a promise like that, just use fetch:
function doGET(url) {
return fetch(url).then(response => {
if (!response.ok) {
throw new Error("HTTP error " + response.status); // Rejects the promise
}
});
}
Since you want to handle the local file, Try this
Make use of XMLHttpRequest
function readFile(file)
{
var f = new XMLHttpRequest();
f.open("GET", file, false);
f.onreadystatechange = function ()
{
if(f.readyState === 4)
{
if(f.status === 200 || f.status == 0)
{
var res= f.responseText;
alert(res);
}
}
}
f.send(null);
}
Then you have to call with File:\\
readFile('File:\\\yourpath');
I'm trying to chain some API calls before setting the textContent of some spans in my webpage. I can execute the following ajax API calls separately by pasting them into the console, but when I chain them as promises I get getFirstData() is undefined.
var first_data = [],
second_data = [];
function getFirstData(){
var xhr = new XMLHttpRequest();
var url = "/API/first-data?format=json"
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
first_data = JSON.parse(xhr.responseText);
return Promise.resolve('1');
}
}
xhr.open("GET", url, true);
xhr.send();
}
/*getSecondData is the same, but with a different API url. I'll DRY these
two into one function that takes a url argument when I get it working.*/
getFirstData().then(getSecondData).then(createPage);
This is between <script> tags just before </body>. So what's wrong with the call to getFirstData() on the last line that causes the interpreter to say it's undefined? For reference, in the network log, getSecondData() is sent and returns just fine.
(Note: I'm specifically trying to do this without JQuery).
The issue occurs because your function is returning undefined (in other words, getting to the end of the function block before it returns) before it ever gets a chance to return Promise.resolve('1').
Your function has to immediately return a Promise object, which becomes pending before eventually resolving inside your AJAX handler.
I'd also add error handling using the provided reject argument, as is standard for Promise objects.
function getFirstData(){
return new Promise(function(resolve, reject) { // encapsulate code in a promise which returns immediately
var xhr = new XMLHttpRequest();
var url = "/echo/json"
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
first_data = JSON.parse(xhr.responseText);
return resolve('1');
}
else {
return reject('There was an error!') // reject the promise if error occurs
}
}
xhr.open("GET", url, true);
xhr.send();
});
}
And then catch it in the thenable chain:
getFirstData()
.then(getSecondData)
.catch(function(err){Throw err}) // catch the error if it throws
.then(createPage);
See working jsfiddle
getFirstData isn't returning a promise it returns undefined, which is not thenable.
function getFirstData(){
return new Promise(function(resolve) {
var xhr = new XMLHttpRequest();
var url = "/API/first-data?format=json"
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
first_data = JSON.parse(xhr.responseText);
resolve('1');
}
}
xhr.open("GET", url, true);
xhr.send();
});
}