Why it exists or do you mean understanding code that makes heavy use of callbacks? Just curious…
Well, I am used to call a function about this way (rough pseudocode):
func main() {
data := get_data() //call the function
alert(data)
//use the data without callback
}
func get_data() data string {
data := fetch() something
return data //return data to main function
}
But using Javascript you cannot return any data directly from a fetch() I have been told from experts. You have to use it within the function. I think this is odd. Hard to rethink for me.
Well you kinda can, but I think I understand your point. To use a more concrete example (source), consider the following Ruby code:
require 'net/http'
require 'json'
url = 'https://api.github.com/users/jameshibbard'
uri = URI(url)
response = JSON.parse(Net::HTTP.get(uri))
puts response['public_repos']
puts 'Hello!'
As one might expect, this code makes a request to the GitHub API to fetch my user data. It then parses the response, outputs the number of public repos attributed to my GitHub account and finally prints “Hello!” to the screen. Execution goes from top to bottom.
Contrast that with the equivalent JavaScript version:
fetch('https://api.github.com/users/jameshibbard')
.then(res => res.json())
.then(json => console.log(json.public_repos));
console.log('Hello!');
If you run this code, it will output “Hello!” to the screen, then after a short delay, the number of public repos attributed to my GitHub account.
Does this describe the concept you are having trouble wrapping your head around?
Not exact. This is more how I want it to work. Call a function and get a result.
alert(get_data()) I e call a function and return values. Logic to me, but not logic in Javascript. You have to think backwards sort of.
alert(get_data())
function get_data() {
let url = 'https://api3.go4webdev.org/tsk/all';
fetch(url, {
method: 'GET',
})
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error('Network response was not ok');
}
})
.then(data => {
console.log(data);
})
.catch(error => {
// Handle errors here
console.error(error);
});
}
There are various ways of making this work.
You could use a wrapping function, main()
in this case:
async function main() {
const data = await get_data(); // Wait for data
alert(JSON.stringify(data)); // Alert data
}
function get_data() {
let url = 'https://api3.go4webdev.org/tsk/all';
return fetch(url, {
method: 'GET',
})
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error('Network response was not ok');
}
});
}
main();
An IFFE:
(async () => {
async function get_data() {
let url = 'https://api3.go4webdev.org/tsk/all';
const response = await fetch(url, { method: 'GET' });
if (response.ok) {
return await response.json();
} else {
throw new Error('Network response was not ok');
}
}
const data = await get_data(); // Wait for data
alert(JSON.stringify(data)); // Alert data
})();
Or if you are in a context that can deal with a top-level await (e.g. a JS module):
async function get_data() {
let url = 'https://api3.go4webdev.org/tsk/all';
const response = await fetch(url, { method: 'GET' });
if (response.ok) {
return await response.json();
} else {
throw new Error('Network response was not ok');
}
}
const data = await get_data(); // Wait for data
alert(JSON.stringify(data)); // Alert data
Error handling makes the code a lot uglier:
async function get_data() {
let url = 'https://api3.go4webdev.org/tsk/all';
const response = await fetch(url, { method: 'GET' });
if (response.ok) {
return await response.json();
} else {
throw new Error('Network response was not ok');
}
}
let data; // if you need it outside the try...catch block.
try {
data = await get_data(); // Wait for data
alert(JSON.stringify(data)); // Alert data
} catch (error) {
console.error(error);
}
Which is sometimes why I tend to prefer the .then()
syntax.
Well this is more the linear way of thinking. Thank you! Now I beginning slowly to like Javascript
But there is still not a “call” from one function to another. You have to call the calling function. IMHO.
But all the others give errors.
The IFFE works for me in JS fiddle. You are not in a module, so top-level await will not work.
Declaring a module is simple, though. If running in the browser, include your code like so:
<script src="index.js" type="module"></script>
Let’s leave it there, as we are taking the original question way off topic
Happy to discuss in another thread though if you have any questions.
Yes, but you do not “call” this function. The response is called from inside the fetch(). Or am I missing something?
In my dreams i want to call from an outside function to a fetch and return values.
OP had a question why it is so hard to learn Javascript. So it is still within the subject of “why” it is hard to learn. IMO.
But I agree it is way more specific than the generic “I do not like Javascript”
I don’t follow. Which function do you mean? get_data
is called here:
const data = await get_data();
You are obviously in good hands with James here, but just as an aside this is how I picture callback hell
function fetchName(callback) {
return callback({
first: 'John',
last: 'Smith'
})
}
function joinNames(name, callback) {
return callback(`${name.first} ${name.last}`)
}
function toUpper(name, callback) {
return callback(name.toUpperCase())
}
// callback hell with nested callbacks
fetchName((name) => {
joinNames(name, (fullName) => {
toUpper(fullName, (fullNameUpper) => {
console.log(fullNameUpper)
})
})
})
As opposed to with promises
function fetchName() {
return Promise.resolve({
first: 'John',
last: 'Smith'
})
}
function joinNames(name) {
return Promise.resolve(`${name.first} ${name.last}`)
}
function toUpper(name) {
return Promise.resolve(name.toUpperCase())
}
// no nesting
fetchName()
.then((names) => joinNames(names))
.then((fullName) => toUpper(fullName))
.then((fullNameUpper) => console.log(fullNameUpper))
I think you have that down though
From ONE function to another function. Not within the same function
Like
function main() {
var data = get_data()
// do something with data
}
function get_data() {
let url = 'https://api3.go4webdev.org/tsk/all';
return fetch(url, {
method: 'GET',
})
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error('Network response was not ok');
}
});
}
Well, your code made me really dizzy. But it is Saturday evening here, so I can reduce the wine consumption
It made me dizzy too.
I’m on the single malt, so join the club
Just make it async
and it works as expected.
async function main() {
const data = await get_data();
console.log(data);
}
function get_data() {
const url = 'https://api3.go4webdev.org/tsk/all';
return fetch(url, {
method: 'GET',
})
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error('Network response was not ok');
}
});
}
main();
I know James isn’t a fan of the try/catch approach and there are more elegant approaches to this, but for consistency and following MDN’s approach.
async function main() {
const data = await get_data('https://api3.go4webdev.org/tsk/all');
console.log(data);
}
// passing in a url instead, so not tightly coupled to that one address
async function get_data(url) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error("Network response was not OK");
}
return await response.json();
} catch (error) {
console.error("There has been a problem with your fetch operation:", error);
}
}
Nice. As a Javascript newbie I find this more readable, but how do I add POST, GET and Authorization / Bearer to this? This will not work:
async function main() {
const data = await get_data('https://api3.go4webdev.org/tsk/all');
console.log(data);
}
// passing in a url instead, so not tightly coupled to that one address
async function get_data(url) {
try {
const response = await fetch(url),
{
method: 'GET',
headers: {
'Authorization': 'Bearer 12345892hjk',
},
}
if (!response.ok) {
throw new Error("Network response was not OK");
}
return await response.json();
} catch (error) {
console.error("There has been a problem with your fetch operation:", error);
}
}
main()
EDIT. I think I got it.
const response = await fetch(url, {
method: 'GET',
headers: {
'Authorization': 'Bearer 12345892hjk',
},
})
OK?
EDIT2:
const data = await get_data('https://api3.go4webdev.org/tsk/all');
...
return await response.json();
Do I really need 2 await?
You need to await anything that returns a Promise object if you want the result of the promise rather than the promise itself. The response.json()
method returns a promise that is resolved with the JSON data, so you need to await it if you want the data rather than the promise.
So I need double await? This can lead to incomplete answer?
I missed the overall context, no you don’t need to await on the return, the await on the call is enough.
This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.