You are not being considerate of other peopleâs effort in helping you learn. You really need to learn how to read and try your very best to understand before you ask questions.
Most people who have tried to help or are still helping you wonât give you the complete solutionâbecause they know that by giving you the solution, they would be doing both you and themselves a disfavour.
Thatâs also why I only posted a link as a response to this thread because you started two other threads related to this, and a few other ones on other parts of the projects. At this rate everyone may just stop responding and be reluctant to help in the future.
Donât just copy and paste code that people show you and then come back when things donât work. The beauty about coding is that, most of the time, you know itâs your fault when things donât work. Ask yourself why it doesnât work and test the living daylight out of it first. There are no secrets to figuring out whatâs wrongâcheck your error log and try to find where things break and see if you are getting the responses you expect with this handy little tool:
console.log()
There is no point in even debugging your current code because you havenât actually taken the time to learn how to work with what everyone has suggested so far. The more you code like this the more you will allow yourself to code like this.
If you are actually a chemist then you should be taking a similar approach to when you do chemistryâfor example, like how the common experiment of calculating the heats of reaction between sodium hydroxide and hydrochloric acid with Hessâs Law requires you to break the process down into smaller pieces, solving them bit by bit, and then adding them all back up to get the answer.
What you should be doing right now, instead of asking more questions, is to start a new Pen on CodePen, import jQuery and do this:
const reactants = ["H2O(l)"];
console.log("I expect this to be printed first.")
jQuery.getJSON("https://enthalpy-api.herokuapp.com/" + reactants[0], function(result) {
console.log("I expect this to be printed last: ", result);
});
console.log("I expect this to be printed second.")
Then you need to ask yourself whether or not you are comfortable with the output that you see in the log, if so, then you need to remember that jQuery.getJSON()
returns jqXHR object. It may look confusing and have nothing to doâbut it has been mentioned that it has the property of a Promise and also provided a reference to a while ago. Upon closer inspection of the documentation again, you realise that the jqXHR.then(function( data, textStatus, jqXHR ) {}, function( jqXHR, textStatus, errorThrown ) {});
looks like what @psychometry suggested, so you go back to experiment with it:
jQuery.getJSON("https://enthalpy-api.herokuapp.com/" + reactants[0], function(result) {
console.log("I expect this to be printed first: ", result);
})
.then(function(data) {
console.log("I expect this to be printed last: ", data);
});
By this point something that you have been struggling must have clicked, but it still doesnât look exactly like what everyone has shown you, like the jQuery.when()
thing, for example. At this point you remember that @psychometry said that it shouldnât work if you pass it a function and that it requires an (jqXHR in this case) object. Can I wrap the whole jQuery.getJSON()
thing inside jQuery.when()
, since it returns an object? You then go experiment with it again:
const reactants = ["H2O(l)"];
jQuery.when(jQuery.getJSON("https://enthalpy-api.herokuapp.com/" + reactants[0], function(result) {
console.log("I expect this to be printed first: ", result);
}))
.then(function(data) {
console.log("I expect this to be printed last: ", data);
});
Whoa, that worked! That looks pretty messy thoughâbut thatâs okay, because @psychometry has shown me that I can simply assign it to a variable. You then try assigning the response to a variable since itâs simply an object:
const reactants = ["H2O(l)"];
const meowed = jQuery.getJSON("https://enthalpy-api.herokuapp.com/" + reactants[0], function(result) {
console.log("I expect this to be printed first: ", result);
});
jQuery.when(meowed)
.then(function(data) {
console.log("I expect this to be printed last: ", data);
});
That worked great! How about as a function?
const reactants = ["H2O(l)"];
function meow() {
jQuery.getJSON("https://enthalpy-api.herokuapp.com/" + reactants[0], function(result) {
console.log("I expect this to be printed first: ", result);
});
}
jQuery.when(meow)
.then(function(data) {
console.log("I expect this to be printed last: ", data);
});
That doesnât work and you are printing the entire function in the log. You have no idea what is going on but you decided to push ahead and try different things because you really want to understand this. Since jQuery.when()
accepts a jqXHR object, it must mean that nothing is actually getting⊠returned by the function! You try again:
const reactants = ["H2O(l)"];
function meow() {
return jQuery.getJSON("https://enthalpy-api.herokuapp.com/" + reactants[0], function(result) {
console.log("I expect this to be printed first: ", result);
});
}
jQuery.when(meow)
.then(function(data) {
console.log("I expect this to be printed last: ", data);
});
But it still doesnât work and you are effectively getting the same result with an extra return
printed. At this point you either go for a walk and come back to it, or you politely ask someone on the forums. It turns out that you are just missing some bracketsâafter all, you are calling a function so that it can return a jqXHR object after itâs done:
const reactants = ["H2O(l)"];
function meow() {
return jQuery.getJSON("https://enthalpy-api.herokuapp.com/" + reactants[0], function(result) {
console.log("I expect this to be printed first: ", result);
});
}
jQuery.when(meow())
.then(function(data) {
console.log("I expect this to be printed last: ", data);
});
Now that you have the basics somewhat mastered, you decide to tackle a slightly larger problemâgetting multiple enthalpies and make sure that you can still control the order of execution. After getting distracted and learned how to use arrow functions, you then start with this:
const reactants = ["H2O(l)", "O2(g)", "H2(g)"];
reactants.forEach((reactant) => {
jQuery.getJSON("https://enthalpy-api.herokuapp.com/" + reactant, (result) => {
console.log(result);
});
});
That worked kind of as expectedâyou remember that the whole point of this exercise is that you had problems with asynchronous jQuery.getJSON() calls
so you logged the response a few times and found out that the results returned are not in the same order as the array supplied. Being careful, you think you will the index of the reactant as well just to be sure:
const reactants = ["H2O(l)", "O2(g)", "H2(g)"];
reactants.forEach((reactant, index) => {
console.log(index);
jQuery.getJSON("https://enthalpy-api.herokuapp.com/" + reactant, (result) => {
console.log(result);
});
});
ARGH, why are the indicies getting printed before any of the enthalpies are returned!? But then you calmed down because you just learned how to use .then()
earlier:
const reactants = ["H2O(l)", "O2(g)", "H2(g)"];
reactants.forEach((reactant, index) => {
jQuery.getJSON("https://enthalpy-api.herokuapp.com/" + reactant, (result) => {
console.log(result);
})
.then((data) => {
console.log(index);
});
});
Itâs actually worse than before and the enthalpies and indicies are actually all jumbled up. You think through it step by step carefully and came to the conclusion all three API calls must be getting executed at different times and whenever the processor has time to get to themâthe results are probably also different every time because, well, black magic, maybe the server responses at different times, too. Thatâs irrelevant, though, because you are convinced that you need some way to control the order that data comes through and thatâs the only solution. It then becomes obvious that you can simply log the result within .then()
:
const reactants = ["H2O(l)", "O2(g)", "H2(g)"];
reactants.forEach((reactant, index) => {
jQuery.getJSON("https://enthalpy-api.herokuapp.com/" + reactant, (result) => {
/* console.log(result); */
})
.then((data) => {
console.log(index, data);
});
});
After checking that the indicies do indeed match with the reactants and enthalpies returned, you then find a way to store that data for use later in exactly the order that they should be. You know that they donât need to be in that order for heats of reactions to be calculated, but you think that you may need them later for presentational purposes:
const reactants = ["H2O(l)", "O2(g)", "H2(g)"];
const reactantData = reactants.map((reactant) => {
return "";
});
reactants.forEach((reactant, index) => {
jQuery.getJSON("https://enthalpy-api.herokuapp.com/" + reactant, (result) => {
/* console.log(result); */
})
.then((data) => {
/* console.log(index, data); */
reactantData[index] = data;
console.log(reactantData);
});
});
Then you realise that it doesnât actually help the moment you include a console.log()
after the for loop to check:
const reactants = ["H2O(l)", "O2(g)", "H2(g)"];
const reactantData = reactants.map((reactant) => {
return "";
});
reactants.forEach((reactant, index) => {
jQuery.getJSON("https://enthalpy-api.herokuapp.com/" + reactant, (result) => {
/* console.log(result); */
})
.then((data) => {
/* console.log(index, data); */
reactantData[index] = data;
console.log(reactantData);
});
});
console.log("Meow!") /* This gets printed first */
You know you need some way to make sure that all three API calls are finished before you do anything else. So with what you know and comfortable with, you try to come up with a way to count the number of requests that have been done before anything else is done. With the guidance of the MDN documentation, so wrap the for loop inside a Promise and make sure that the promise is resolved only when reactantData
has been filled:
const reactants = ["H2O(l)", "O2(g)", "H2(g)"];
const reactantData = reactants.map((reactant) => {
return "";
});
new Promise((resolve, reject) => {
reactants.forEach((reactant, index) => {
jQuery.getJSON("https://enthalpy-api.herokuapp.com/" + reactant, (result) => {
/* console.log(result); */
})
.then((data) => {
/* console.log(index, data); */
reactantData[index] = data;
if (reactantData.indexOf("") === -1) {
console.log("Meow!")
resolve("All done!");
}
});
});
})
.then((resolve) => {
console.log(resolve);
});
YAY! It works! So you wrap it inside jQuery.when()
again and include another one for products:
const reactants = ["H2O(l)", "O2(g)", "H2(g)"];
const products = ["H2O(l)", "O2(g)", "H2(g)"];
const reactantData = reactants.map((reactant) => {
return "";
});
const productsData = products.map((products) => {
return "";
});
console.log("This should be printed first!");
jQuery.when(
new Promise((resolve, reject) => {
reactants.forEach((reactant, index) => {
jQuery.getJSON("https://enthalpy-api.herokuapp.com/" + reactant, (result) => {
/* console.log(result); */
})
.then((data) => {
/* console.log(index, data); */
reactantData[index] = data;
if (reactantData.indexOf("") === -1) {
console.log("Reactants!")
resolve("All done!");
}
});
});
}),
new Promise((resolve, reject) => {
products.forEach((product, index) => {
jQuery.getJSON("https://enthalpy-api.herokuapp.com/" + product, (result) => {
/* console.log(result); */
})
.then((data) => {
/* console.log(index, data); */
productsData[index] = data;
if (productsData.indexOf("") === -1) {
console.log("Products!")
resolve("All done!");
}
});
});
})
)
.then((resolve) => {
console.log(resolve)
console.log(reactantData);
console.log(productsData)
/* Do calculations */
});
Itâs definitely not the prettiest of code, but at least now you spent the hard work in reading and understanding whatâs happening and, hopefully, through experimentâand if you bothered reading all of that and working it through bit by bit, you should now be in a much better position to use one of the more elegant solutions that @honmanyau, @RadDog25, @psychometry suggested.
I feel much better now.
Good luck! o: