| And now for promises. Why promises? Before promises, js code often used an error first callback strategy to communicate when an asynchronous process has finished. It's important to write blocking code as little as possible, since your computer can and should spend time doing 'compute' stuff, whilst waiting for a resource, such as a network request or disk etc.. which can take an unbounded amount of time. Back to how callbacks look:
```
function myExpensiveSuccessfulFn(cbFn) {
setTimeout(() => {
cbFn(null, 'success'); // pretend we did something useful
}, 60 * 1000) // time waste for a minute
} function myExpensiveFailingFn(cbFn) {
setTimeout(() => {
cbFn('oh no'); // pretend we tried to do something useful
}, 60 * 1000) // time waste for a minute
} function myCallback(err, data) {
console.log(`err: ${err}`);
console.log(`data: ${data}`);
} myExpensiveSuccessfulFn(myCallback);
// after 1 minute: err: null, data: 'success' myExpensiveFailingFn(myCallback);
// after 1 minute: err: 'oh no', data: undefined
``` Awesome. We can wait for some result and be notified whenever it finishes. Have a play in your inspector as before.
Immediately after calling our expensive functions, we can execute code straightaway (try logging anything immediately after calling an expensive function) Now callbacks start to get unwieldy when those same callbacks also want to do things that require something else asynchronously. There are better examples online, but I'll write something with anonymous functions to give you an idea: ```
function addSomethingSoon(a, b, cbFn) {
// in 5 seconds, return the sum of two numbers
setTimeout(() => {
cbFn(a + b)// no err first style in this example
}, 5 * 1000);
} // now let's get the sum of four numbers: addSomethingSoon(1, 2, (result1) => {
addSomethingSoon(result1, 3, (result2) => {
addSomethingSoon(result2, 4, (finalResult) => {
console.log(`1+2+3+4=${finalResult}`);
});
});
});
``` Only 3 operations, and things are getting quite ugly. Contrived, but let's see how we can do better. Enter the promise. A promise is a 'promise' of a future result. It's like if you went to a fast food restaurant, made an order and got a ticket in return. Once you are given a ticket, they'll call out your number and give you your food, since you are holding the ticket (the promise of food in the future). Let's have a play: ```
function getFoodIn5(menuItem) {
// don't worry about the syntax here. You'll likely not be creating promises with 'new' often. You'll likely get given them from a library, say a http call or similar.
return new Promise((onComplete) => {
setTimeout(() => {
onComplete(`fresh ${menuItem}`);
}, 5 * 1000)
});
} const promiseOfFood = getFoodIn5('burger');
console.log(promiseOfFood) // depends on your browser, nothing very useful, and definitely NOT our burger.... promiseOfFood.then((food) => {
console.log(food); // fresh burger, yes, it tastes so good!
});
``` So we got our burger, pretty fast too. Unfortunately they just hired a few trainees: ```
function burntFoodIn5(menuItem) {
// don't worry about the syntax here. You'll likely not be creating promises with 'new' often. You'll likely get given them from a library, say a http call or similar.
return new Promise((onComplete, onError) => {
setTimeout(() => {
onError(`burnt ${menuItem}`);
}, 5 * 1000)
});
} const promiseOfFood = burntFoodIn5('burger');
console.log(promiseOfFood); promiseOfFood.then((food) => {
console.log(food); // ... :( nothing
}).catch((mistake) => {
console.log(mistake) // burnt burger, you don't want to eat this.
});
``` that is promises in a nutshell. doesn't seem very useful now, but they are composable: ```
function add2(a, b) {
// return a promise NOW, that will give us the sum of two numbers in 5
return new Promise((onComplete) => {
setTimeout(() => {
add2(a + b)
}, 5 * 1000);
});
} add2(1, 2).then((result1) => {
return add2(result1, 3);
}).then((result2) => {
return add2(result2, 4);
}).then((finalResult) => {
console.log(`1+2+3+4=${finalResult}`);
});
``` Now we don't have the masses of indentation of callback hell. Note that will take the same amount of time to run as the callback example. Promises don't make anything faster, they just help us to write synchronous looking code. The next step to bring us back to imperative looking code is async/await. But that's for another time. Finally, the best way to learn is to do. Get a hold of VSCode, and get the Quokka extension. You can then `Ctrl+Shift+P` or `Cmd+Shift+P` and `Quokka: new javascript file`, and get a real time repl where you can mess around and log to your hearts content to get a feel of things. |