I have the following method.
async getuserdevicesIDs() {
let timesDone = 0;
// tslint:disable-next-line: no-var-keyword
const viewDevicesLink = '/user/devices/view/'; // parameter: email
const xhr = new XMLHttpRequest();
// xhr.open('POST', this.AUTH_SERVER_ADDRESS + '/user/devices/view/', true);
xhr.open('POST', this.AUTH_SERVER_ADDRESS + viewDevicesLink, true);
xhr.setRequestHeader('Content-type', 'application/JSON;charset=UTF-8');
console.log(this.auth.getUserID());
const email = this.auth.getUserID().toString();
const us = new User();
us.name = '';
us.email = 'richard#gmail.com';
us.password = '';
xhr.send(JSON.stringify(us));
xhr.addEventListener('readystatechange', processRequest, false);
xhr.onreadystatechange = processRequest;
function processRequest(e) {
// tslint:disable-next-line: triple-equals
if (xhr.readyState == 4 && xhr.status == 200) {
// tslint:disable-next-line: triple-equals
if (timesDone == 0) {
// tslint:disable-next-line: prefer-const
const response = xhr.response;
timesDone++;
return response;
}
// tslint:disable-next-line: triple-equals
} else if (xhr.readyState == 4) {
alert('server error: ' + xhr.status + ', response is: ' + xhr.responseText);
timesDone++;
return null;
}
}
}
that is working fine but when i call the method like this
var IDs = await this.getuserdevicesIDs();
alert(IDs[0]);
then the alert fires before the getuserdevicesIDs() method has completed even if I await it. Any idee on how i can force the alert to wait for the method to finish? Thanks for any help
Try returning a Promise inside getuserdevicesIDs() function like this
async getuserdevicesIDs() {
return await new Promise((resolve, reject) => {
//your code here ...
resolve(value); // when you want to return a value in promise
}
}
When you want to call the method
this.getuserdevicesIDs().then(response => {}).catch(err => {});
Related
I have this code
async function dataget(APIURL){
let x = false;
let xhr = new XMLHttpRequest();
xhr.open("GET", APIURL);
xhr.send();
xhr.onload = await function(){
if(1 == 1){
x = true
}else{
x = "gg"
}
}
console.log(x)
}
console.log(dataget("data.json"));
I want console to wait until onload function ends (when x = true), but this doesn't happen,
console returns false and doesn't wait
this is the output:
I want an explanation not just the solve
You need to turn the dataget function to return a promise which will resolve after the onload function executed, so you can await it and return the result.
function dataget(APIURL){
return new Promise((resolve, reject) => {
let x = false;
let xhr = new XMLHttpRequest();
xhr.open("GET", APIURL);
xhr.send();
xhr.onload = function(){
if(1 == 1){
resolve(true)
}else{
resolve("gg")
}
}
})
}
(async () => {
const result = await dataget("data.json")
console.log(result); // true
})()
Here's one way to make the code do what you want
async function dataget(APIURL) {
const x = await new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open("GET", APIURL);
xhr.send();
xhr.onload = () => {
if (1 == 1) {
resolve(true);
} else {
resolve("gg");
}
};
});
console.log(x);
return x;
}
(async () => {
console.log(await dataget("data.json"));
})();
I have the following methods.
async getuserdevicesIDs() {
return await new Promise( (resolve, reject) => {
let timesDone = 0;
// tslint:disable-next-line: no-var-keyword
const viewDevicesLink = '/user/devices/view/'; // parameter: email
const xhr = new XMLHttpRequest();
// xhr.open('POST', this.AUTH_SERVER_ADDRESS + '/user/devices/view/', true);
xhr.open('POST', this.AUTH_SERVER_ADDRESS + viewDevicesLink, true);
xhr.setRequestHeader('Content-type', 'application/JSON;charset=UTF-8');
console.log(this.auth.getUserID());
const email = this.auth.getUserID().toString();
const us = new User();
us.name = '';
us.email = 'richard#gmail.com';
us.password = '';
xhr.send(JSON.stringify(us));
xhr.addEventListener('readystatechange', processRequest, false);
xhr.onreadystatechange = processRequest;
function processRequest(e) {
// tslint:disable-next-line: triple-equals
if (xhr.readyState == 4 && xhr.status == 200) {
// tslint:disable-next-line: triple-equals
if (timesDone == 0) {
// tslint:disable-next-line: prefer-const
const response = xhr.response;
timesDone++;
alert(response);
resolve(response);
}
// tslint:disable-next-line: triple-equals
} else if (xhr.readyState == 4) {
alert('server error: ' + xhr.status + ', response is: ' + xhr.responseText);
timesDone++;
return null;
}
}
});
}
This method ask the server for certain values and The server will return an arrya of values but I do not know how to resolve the response as an arry for later use in this method.
this.getuserdevicesIDs().then(response => {
alert(this.IDs); })
.catch(err => {});
If anyone knows how i can store the response i get from server into an array that would help me out a great deal. Thank you
When receiving data from a web server, the data is always a string.
Parse the data with JSON.parse(), and the data becomes a JavaScript object.
resolve(JSON.parse(response));
How to use promises (ES6) and .then method in order to this code will work?
getGif: function (searchingText, callback) {
var url = GIPHY_API_URL + '/v1/gifs/random?api_key=' + GIPHY_PUB_KEY + '&tag=' + searchingText;
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onload = function () {
if (xhr.status === 200) {
var data = JSON.parse(xhr.responseText).data;
var gif = {
url: data.fixed_width_downsampled_url,
sourceUrl: data.url
};
callback(gif);
}
};
xhr.send();
},
Using Promise-Based XHR your code looks like:
getGif = function (searchingText) {
return new Promise((resolve, reject)=>{
var url = GIPHY_API_URL + '/v1/gifs/random?api_key=' + GIPHY_PUB_KEY + '&tag=' + searchingText;
var xhr = new XMLHttpRequest();
// Setup our listener to process compeleted requests
xhr.onreadystatechange = function () {
// Only run if the request is complete
if (xhr.readyState !== 4) return;
// Process the response
if (xhr.status >= 200 && xhr.status < 300) {
// If successful
var data = JSON.parse(xhr.responseText).data;
var gif = {
url: data.fixed_width_downsampled_url,
sourceUrl: data.url
};
resolve(gif);
} else {
// If failed
reject({
status: request.status,
statusText: request.statusText
});
}
};
xhr.open('GET', url);
xhr.send();
});
}
Need to invoke method depends on signature of function.
getGif(searchText).then((response)=>{
console.log(response);
}, (error)=> {
console.log(error);
})
I use an XMLHttpRequest inside a Promise. Because the server sometimes is idle, I would like to do 3 attemps when there is an error.
However, doing like below raise the Object state must be opened error on line xhr.send() in the function sendData(). Why?
I think the xhr is already opened. What would be the proper way to achieve this?
function _callService(url, postData) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
var attempts = 0;
xhr.open("POST", url);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
resolve(xhr.response);
}
}
};
xhr.addEventListener("error", onXhrError);
function sendData() {
//here I get the Object state must be opened when this is called from onXhrError listener
xhr.send(postData);
};
function onXhrError() {
console.log("onXhrError");
if (attempts < 3) {
attempts += 1;
sendData();
} else {
reject("OnXhrError")
}
};
sendData();
});
Schedule _callService(url, postData, attempts) to be called again instead of sendData(), see multiple, sequential fetch() Promise.
function callService(attempts) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
if (attempts < 3)
reject(++attempts)
else
resolve("done");
}, Math.floor(Math.random() * 1200))
}).catch(function(err) {
throw err
})
}
function request(n) {
return callService(n)
.then(function(data) {
console.log(data);
return data
})
.catch(function(err) {
console.log(err);
return typeof err === "number" && err < 3 ? request(err) : typeof err !== "number" ? new Error(err) : "requested " + err + " times";
})
}
request(0)
.then(function(done) {
console.log("done:", done)
})
.catch(function(err) {
console.log(err)
})
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
I'm trying to return a value from an onreadystatechange AJAX call... I found this page : stackoverflow link. I though I had it working but realised that it made no difference to add or remove the fn function. The following code works :
username_is_available();
function username_is_available() {
var username = document.getElementById('username').value;
get_data('username', username, function(returned_value) {
if (returned_value == 'true') {
document.getElementById('username_err').innerHTML = 'Taken';
} else {
document.getElementById('username_err').innerHTML = 'Available';
};
});
}
function get_data(data_type, data, fn) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
fn(xmlhttp.responseText);
}
};
xmlhttp.open("GET", "availability.php?" + data_type + "=" + data, true);
xmlhttp.send();
}
It all works fine but that's not my goal, I would like a function username_is_available() that returns true if the username is indeed available.
Instead, here I an action happens (innerHTML is changed). And if I try and do a return in the anonymous function I get the same result as if I had returned it from directly inside the onreadystatechange : var unasigned
Unfortunately, since the process to determine if a username is taken is asynchronous, there is no way to simply return a value of true or false from the function call. What you can do is set up something similar to what you have now (callbacks) using language features specifically designed for this exact purpose.
A Promise is one of these features.
Usage would look something roughly like this:
function username_is_available(username) {
return new Promise(resolve => {
get_data("username", username, resolve);
});
}
function get_data(data_type, data, fn) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
fn(xmlhttp.responseText == "true");
}
};
xmlhttp.open("GET", "availability.php?" + data_type + "=" + data, true);
xmlhttp.send();
}
// Usage:
username_is_available("Ivan").then(available => {
let text = available ? "Available" : "Taken";
document.getElementById("username_err").innerHTML = text;
});
This relies on availablity.php returning true and false as text, which is converted to a Boolean before resolve is called.
In the future, when ES7+ async and await directives are available, using the promise will be as simple as this (note the await keyword):
let available = await username_is_available("Ivan");
let text = available ? "Available" : "Taken";
document.getElementById("username_err").innerHTML = text;
Edit: If you can't use ES6 or promises, it's back to good ol' callbacks!
function username_is_available(username, callback) {
get_data("username", username, callback);
}
function get_data(data_type, data, fn) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
fn(xmlhttp.responseText == "true");
}
};
xmlhttp.open("GET", "availability.php?" + data_type + "=" + data, true);
xmlhttp.send();
}
// Usage:
username_is_available("Ivan", function(available) {
var text = available ? "Available" : "Taken";
document.getElementById("username_err").innerHTML = text;
});
I've been playing around with observers as an alternative to promises. I set up a an example in plnkr to show how it can work. I think in your case it would look like this:
function Producer() {
this.listeners = [];
}
Producer.prototype.add = function(listener) {
this.listeners.push(listener);
};
Producer.prototype.remove = function(listener) {
var index = this.listeners.indexOf(listener);
this.listeners.splice(index, 1);
};
Producer.prototype.notify = function(message) {
this.listeners.forEach(function(listener) {
listener.update(message);
});
};
var notifier = new Producer;
function get_data(data_type, data) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
notifier.notify(xmlhttp.responseText);
}
};
xmlhttp.open("GET", "availability.php?" + data_type + "=" + data, true);
xmlhttp.send();
}
var username_is_available = {
update: function(returned_value) {
var username = document.getElementById('username').value;
if (returned_value == 'true') {
document.getElementById('username_err').innerHTML = 'Taken';
} else {
document.getElementById('username_err').innerHTML = 'Available';
};
}
}
notifier.add(username_is_available);
get_data("username", username);
Note the Producer code is reusable, you would make a new instance for other ajax/observable requests.