In JavaScript How Do I/Should I Use Async/Await with Xmlhttprequest

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:

  1. Asynchronous is not the same as on another thread. You're still blocking the main UI thread.

  2. The promise executor function (the function you pass to new Promise) is executed synchronously anyway. So your call 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



Leave a reply



Submit