Your call to console.log is being executed before the request has finished and the data has been received.
The order of execution differs from the order your code is written. The likely chain of events is:
- Create undefined variable named
data
- Fire off a request to
/users/login with the fetch API which will be executed asynchronously
- Call to
console.log with a reference to data which is still undefined
- Request has completed, so the callback passed to
fetch.then is called, and data is defined
You'd need to wait until the request is complete and the response is parsed before doing something with data.
You can do this in a couple of different ways. Using promises:
let data;
fetch("/users/login", requestOptions)
.then((response) => response.text())
.then((result) => {
data = JSON.parse(result);
// Now that `data` has been defined, we can do something with it
console.log(data);
})
.catch((error) => console.log("error", error));
With async/await
// Note the async keyword
async function foobar() {
let data;
// Note the await keyword
await fetch("/users/login", requestOptions)
.then((response) => response.text())
.then((result) => {
data = JSON.parse(result);
})
.catch((error) => console.log("error", error));
console.log(data);
}
// There are other improvements that could be made to this example also
// to make it more idiomatic. For example:
async function foobar() {
let data;
// Use try/catch instead of `Promise.catch`
try {
const response = await fetch('/users/login', requestOptions);
// Use the `.json` method on the fetch response object
data = await response.json();
} catch (error) {
console.log('error', error);
}
console.log(data);
}
The important thing to note is that any action that occurs in the context of a promise (in your case, assignment to data will occur asynchronously. The action may or may not have been completed at any given moment.
Using async/await is usually recommend as best practice these days. This requires ES6 support, but that's usually a given in 2020 and has been supported in browsers and Node for years at this point.
Using async/await allows you to write asynchronous code without the dreaded "callback hell" of Promises, and allows you to write more expressive & readable code that closer resembles procedural code.
One thing to bear in mind when using async/await is that the await keyword can only be used in a function that is marked as asynchronous with the async keyword, as in the above example.