Due to the asynchronous nature of JavaScript, promises and callbacks are very important. Both allow us to control the flow of the operations and execute tasks in sequence.
- Fork this repo
- Clone this repo
- Upon completion, run the following commands:
$ git add .
$ git commit -m "done"
$ git push origin master
- Create a Pull Request and submit your assignment.
We provided you with some starter code:
javascript/data.js
- contains four arrays with steps to preparing 4 different foods: mashed potatoes, steak, brussels sprouts and broccoli.
-
javascript/getInstruction.js
- contains a functiongetInstruction
that uses callbacks to asynchronously retrieve instruction steps for any food. It usessetTimeout
to mimic an asynchronous operation.getInstruction(food, step, callback, errorCallback)
❗ You should not make any changes to this file.
-
javascript/obtainInstruction.js
- has a functionobtainInstruction
that uses promises to asynchronously retrieve instruction steps for any food. It also usessetTimeout
to mimic an asynchronous operation.obtainInstruction(food, step)
❗ You should not make any changes to this file either.
javascript/index.js
- in this file we left an example to show you how the code should execute. However, the provided code doesn't use nested callbacks or promises yet, which is why the steps won't print in the correct order. Your task in the first iteration will be to do this properly, but more on that later.
index.html
- contains a base HTML structure needed so no need to add any code there. Previously mentioned JavaScript files are already linked to theindex.html
. Thedata.js
loads first to make sure arrays that hold instructions are already loaded and can be used in other files, where we need them.
❗ You should not make any changes to this file.
You should write your code only in the javascript/index.js
file.
Now, open the file and take a look at the starter code provided there. The provided code doesn't use nested callbacks to enforce a sequence of execution, which is why the steps are not displayed in the correct order.
Go ahead and open the index.html
page in the browser. Notice how the cooking steps are displayed out of order.
❗Before you start working on Iteration 1, comment out the initial code in javascript/index.js
.
Using nested callbacks print the cooking steps to make Mashed Potatoes in the correct order. Write your JavaScript in the provided javascript/index.js
file. Once again, a reminder not to alter the getInstruction.js
file.
// Iteration 1 - using callbacks
getInstruction('mashedPotatoes', 0, (step0) => {
document.querySelector("#mashedPotatoes").innerHTML += `<li>${step0}</li>`
// ... Your code here
// ...
});
After the last step, you should display an additional <li>
with the text: Mashed potatoes are ready!
.
Using promises and the then()
statement print the directions to display the cooking instruction for the Stake in the correct order.
This time, you will have to call the function obtainInstruction
which returns a pending Promise.
Continue working in the javascript/index.js
. You should not alter the obtainInstruction.js
file.
// Iteration 2 - using promises
obtainInstruction('steak', 0)
.then( (step0) => {
document.querySelector("#steak").innerHTML += `<li>${step0}</li>`
// ... Your code here
})
// ... Your code here
After the last step, you should display an additional <li>
with the text: Stake is ready!
.
Using promises with the async
and await
syntax print the directions to make Broccoli in the correct order. You will need to use the function obtainInstruction
which returns a pending Promise.
async function makeBroccoli() {
// ... Your code here
}
After the last step, you should display an additional <li>
element with the text: Broccoli is ready!
.
When the specific food is ready to be served (all steps are listed), remove the hidden
attribute from the <img />
element that represents the food, so that the image gets displayed.
Using Promise.all
display the cooking steps to make Brussels Sprouts in the correct order.
After the last step, you should display an additional <li>
with the text: Brussels sprouts are ready!
.
The final result should look like this - with all the cooking steps displaying in the correct order:
Happy coding! 💙
I am stuck and don't know how to solve the problem or where to start. What should I do?
If you are stuck in your code and don't know how to solve the problem or where to start, you should take a step back and try to form a clear question about the specific issue you are facing. This will help you narrow down the problem and come up with potential solutions.
For example, is it a concept that you don't understand, or are you receiving an error message that you don't know how to fix? It is usually helpful to try to state the problem as clearly as possible, including any error messages you are receiving. This can help you communicate the issue to others and potentially get help from classmates or online resources.
Once you have a clear understanding of the problem, you will be able to start working toward the solution.
How to use then()
and catch()
with Promises?
When working with Promises or a function that returns a promise, you can attach the .then()
method to handle the resolved value and a catch()
method to handle the possible rejection value.
Here is an example of how to use .then()
and .catch()
to handle a simple promise:
myPromise
.then((result) => {
console.log(result);
})
.catch((error) => {
console.log(error);
})
Here is an example of using .then()
and .catch()
to handle a promise returned by a function/method:
someAPI.getData()
.then((result) => {
console.log(result);
})
.catch((error) => {
console.log(error);
})
If you are trying to execute multiple promises in a sequence, you can do so by returning a promise from a .then()
block. Example:
someAPI.getData()
.then((result1) => {
console.log(result1);
return someAPI.getData();
}) // Return another pending promise
.then((result2) => { // Handle the returned promise
console.log(result2);
})
.catch((error) => {
console.log(error);
})
The first line someAPI.getData()
initiates an asynchronous operation, which returns a promise. The .then()
method is then called on the promise to handle the resolved value.
The first then()
returns another promise with another call to someAPI.getData()
, which allows to chain another then()
function that handles the second resolved value, logging it to the console.
How to use async
function and await
?
You create an asynchronous function by using the async
keyword before the function definition.
An async
function allows you to use the await
keyword inside the function body to wait for a promise to resolve.
When using an async
function to handle asynchronous code (e.g. API call) that may potentially throw an error, we have to add a try
/catch
block to be able to handle any potential errors.
async function doSomething() {
try {
// Code that will be executed asynchronously
// that might throw an error
}
catch (error) {
// Handle the error
}
}
Here is an example of using await
inside of an async
function to await for a promise to resolve:
async function getData() {
try {
let response = await fetch('https://api.github.com/search/repositories?q=js');
let data = await response.json();
console.log(data);
}
catch (error) {
// error
}
}
In the above example, the first await
is used to wait for the promise returned by fetch()
to resolve. The value of the resolved promise is then assigned to the variable response
.
The second await
is used to parse the response as json object, and is used to wait for the promise returned by response.json()
. The resolved value is then assigned to the variable data
.
The function uses the return
keyword to return the data
to allow consuming the value outside of the function.
The difference between a regular function and an async
function is that the async
function always returns a Promise.
Once defined, you can invoke an async
function just like a regular function and handle the Promise it returns using .then()
and .catch()
or await
.
Here's an example of using then
and catch
to handle a Promise returned by an async
function:
async function greeting() {
// An `async` function always returns a promise
// This value will be returned as a Promise
return "HELLO IRONHACKERS!";
}
greeting()
.then((result) => {
console.log(result);
})
.catch((error) => {
console.log("Error:", error);
})
Here's an example of handling the same async
function but this time using await
:
async function greeting() {
// Async function always returns a promise
// This value will be returned as a Promise
return "HELLO IRONHACKERS"!;
}
// We need another wrapper `async` function so that we can use `await`
async function wrapperFunction() {
try {
const result = await greeting(
console.log(result);
}
catch (error) {
console.log("Error:", error);
}
}
Note that we needed another wrapper async
function to be able to use await
.
How to use try
/ catch
block?
The try
/catch
block is used to handle errors that occur during the execution of a program.
The try
block contains the code that might throw an error, and the catch
block contains the code that will handle the error.
Here is an example of using a try
/catch
block:
try {
// Code that might throw an error
} catch (error) {
// Handle the error
}
The try
/catch
block is typically used in async
functions when handling asynchronous code that may potentially throw an error.
Here is an example of using a try
/catch
block in an async
function when handling a promise:
async function doSomething() {
try {
// Code that might throw an error
const result = await someAsyncFunction();
}
catch (error) {
// Handle the error
console.error(error);
}
}
In the above example, the try
block contains an asynchronous operation that might throw an error: await someAsyncFunction()
. If an error is thrown, execution will automatically jump to the catch
block.
How to use Promise.all()?
The Promise.all()
method is used for handling multiple promises at the same time. It works in the following way:
-
Promise.all()
takes an array of promises. Example:Promise.all( [promise1, promise2, promise3] )
-
Promise.all()
returns a pending promise, allowing you to handle it with.then()
andcatch()
or withawait
. Example:Promise.all( [promise1, promise2, promise3] ) .then((result) => {}) .catch((error) => {})
-
It resolves successfully only if all input promises are fulfilled. The resolved value is an array of resolved input promises. Example:
Promise.all( [promise1, promise2, promise3] ) .then((values) => { // Resolved value is an array console.log("promise1 value: ", values[0] ); console.log("promise2 value: ", values[1] ); console.log("promise3 value: ", values[2] ); }) .catch((error) => {})
-
If even one of the input promises gets rejected, the returned promise gets rejected with an Error and the execution jumps to the
catch
block.
Here is an example of using Promise.all()
and handling the returned promise with .then()
and .catch()
:
const promise1 = new Promise((resolve, reject) => {
resolve("HELLO");
})
const promise2 = new Promise((resolve, reject) => {
resolve("WORLD");
})
Promise.all( [promise1, promise2] )
.then((values) => {
console.log(values);
})
.catch((error) => {
console.log(error);
})
In the above example, we define two new promises, promise1
and promise2
, and use the Promise.all()
to handle them at the same time.
The Promise.all( [promise1, promise2] )
returns a new promise, that is fulfilled with an array of fulfilled values from the input promises (promise1
and promise2
). We named this array values
.
Here is another example of handling Promise.all()
and the returned promise with await
:
const promise1 = new Promise((resolve, reject) => {
resolve("HELLO");
});
const promise2 = new Promise((resolve, reject) => {
resolve("WORLD");
});
async function handlePromiseAll() {
try {
const values = Promise.all( [promise1, promise2] );
console.log(values);
}
catch (error) {
console.log(error);
}
}
handlePromiseAll()
In the above example, we define two new promises, promise1
and promise2
just as before, and use the Promise.all()
to handle them at the same time.
When working with await
we also need an async
function, which is the reason for having the function handlePromiseAll
.
Inside this function, the await
keyword is used to wait for the returned promise by Promise.all()
to resolve. The resolved value is assigned to the variable values
.
I am getting an error: "not defined". How do I fix it?
The "ReferenceError: variable is not defined" error in JavaScript occurs when you try to access a variable or a function that has not been defined yet or is out of scope.
To fix the issue, check that you have defined the variable or function that you are trying to use and double-check the spelling to make sure you are using the correct name.
In case the variable or a function is defined in another file, make sure that the file has been imported or loaded correctly.
I am unable to push changes to the repository. What should I do?
There are a couple of possible reasons why you may be unable to push changes to a Git repository:
-
You have not committed your changes: Before you can push your changes to the repository, you need to commit them using the
git commit
command. Make sure you have committed your changes and try pushing again. To do this, run the following terminal commands from the project folder:git add . git commit -m "Your commit message" git push
-
You do not have permission to push to the repository: If you have cloned the repository directly from the main Ironhack repository without making a Fork first, you do not have write access to the repository. To check which remote repository you have cloned, run the following terminal command from the project folder:
git remote -v
If the link shown is the same as the main Ironhack repository, you will need to fork the repository to your GitHub account first, and then clone your fork to your local machine to be able to push the changes.
Note: You may want to make a copy of the code you have locally, to avoid losing it in the process.