Async/Await, returned variable is undefined after XHR request
Currently your ninjaGetIp
is not an awaitable Promise
.
You can try just returning a new Promise
that wraps the implementation or just add async
keyword before the function.
function ninjaGetIp() {
return new Promise(function (resolve, reject) {
var ipRequest = new XMLHttpRequest();
ipRequest.open('GET', "https://api.ipify.org?format=jsonp=", true);
ipRequest.send();
ipRequest.onload = function () {
if (ipRequest.status >= 200 && ipRequest.status < 400) { // If response is all good...
return resolve(ipRequest.responseText);
} else {
console.log('There was an error retrieving the public IP.');
return resolve('127.0.0.1');
}
}
});
}
Async sample
async function ninjaGetIp() {
var ipRequest = new XMLHttpRequest();
ipRequest.open('GET', "https://api.ipify.org?format=jsonp=", true);
ipRequest.send();
ipRequest.onload = function () {
if (ipRequest.status >= 200 && ipRequest.status < 400) { // If response is all good...
return ipRequest.responseText;
} else {
console.log('There was an error retrieving the public IP.');
return '127.0.0.1';
}
}
}
Should I call XMLHttpRequest async within promise?
Should I call XMLHttpRequest async within promise?
Yes, asynchronous (not synchronous).
Due to the async nature of the promise, I always assumed that having the
XMLHttpRequest
sync is fine...
It isn't, for a couple of reasons:
Asynchronous is not the same as on another thread. You're still blocking the main UI thread.
The promise executor function (the function you pass to
new Promise
) is executed synchronously anyway. So yourcall
won't return until the ajax call is complete, because it's a synchronous call.
Promises don't change the nature of the work being done. They just provide consistent, standardized syntax for observing the result of work being done (usually asynchronous work, but it doesn't have to be).
The only thing promises make asynchronous is calls to then
, catch
, and finally
handlers. See the comments and results in this snippet for details:
// The promise executor is called *synchronously*.// This outputs 1, 2, 3, not 1, 3, 2:console.log(1);new Promise(resolve => { console.log(2); resolve();});console.log(3);
// `then`, `catch`, and `inally` handlers are called asynchronously, even if// the promise is already settled (because it would be chaotic to call them// synchronously *sometimes* [because the promise is already settled when you// call `then`/`catch/`finally`] but not *other* times [because it isn't// settled yet when you call `then`/`catch/`finally`]).// This outputs A, B, C, not A, C, Bconsole.log("A");Promise.resolve().then(() => console.log("C"));console.log("B");
Ajax and async await
async
/await
is (really useful) syntactic sugar for creating and consuming promises. Your AjaxCall
function implicitly creates a promise, but then also implicitly resolves it immediately with the value undefined
because you never await
anything, and the only return
isn't directly in AjaxCall
but is instead in the onreadystatechange
callback.
You can wrap a promise around XHR, but you don't have to: fetch
already does:
async function Test() {
var result = await fetch("file.php");
if (result.ok) {
alert(await result.text());
}
}
But if you want to do it yourself, you'll need to explicitly create and consume a promise rather than using async
on AjaxCall
:
function AjaxCall(filePath) {
return new Promise((resolve, reject) => {
let xhttp = new XMLHttpRequest();
xhttp.open('POST', filePath, true);
xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhttp.send();
xhttp.onreadystatechange = function() {
if (xhttp.readyState === 4) {
if (xhttp.status === 200) {
resolve(xhttp.responseText);
} else {
reject(); // Probably including some rejection reason
}
}
};
});
}
Where to place async/await in this case?
what function to make async
Simple rule: If function contains await
, it must be marked async
. It changes the semantics of the function so that its return
actually becomes resolution of a promise, and will have no traditional return value; it also says execution of parts of it (those following an await
) will end up being in the future, as opposed to within the current task.
However, you can't delay creation of an object (when constructor returns, it must return a constructed object), so constructor cannot be async
.
You can still output this.data
from code that is within constructor, but not at the time the constructor is executing.
Since constructor must be synchronous in order to construct the object, and AJAX request must be asynchronous(*) in order to give the response time to arrive, I'm letting you know
If I'm going at this in the compltetly wrong approach, then please let me know.
*) This is in fact not true; AJAX call can be synchronous (by passing false
as the third parameter of xhr.open
), but this is heavily discouraged.
Value of Async Function or Value of HTTP Request
function getBasketCode() {
return new Promise((resolve) => {
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = async function () {
if (xhr.readyState == xhr.DONE) {
var code = document.getElementById("shoppingcart_filled").innerHTML;
resolve(code);
}
}
xhr.open('GET', 'https://www.xxxxx.nl/xxxx', true);
xhr.send();
});
}
const code = await getBasketCode(); // assuming you are in an async function, otherwise getBasketCode().then((code) => {...
Related Topics
Difference Between Date(Datestring) and New Date(Datestring)
Getting Title from Wkwebview Using Evaluatejavascript
JavaScript Double Colon (Bind Operator)
The Definitive Best Way to Preload Images Using JavaScript/Jquery
How to Print Part of a Rendered HTML Page in JavaScript
How to Count the Number of Occurrences of Each Item in an Array
How to Make a Shared State Between Two React Components
How to Create an Object from an Array of Key-Value Pairs
Setting Innerhtml VS. Setting Value with JavaScript
Setting a Variable to Get Return from Call Back Function Using Promise
How to Pre-Populate a Jquery Datepicker Textbox with Today's Date
Why Does the Promise Constructor Need an Executor
Angular: Can't Find Promise, Map, Set and Iterator