Async/Await
More Promise Examples (now with Async/Await!)
Quiz 2 will be released at 3 pm today (due tomorrow by 3 pm PST)
At the restaurant you might follow these steps:
Each step can’t continue before the previous finishes.
We can imagine all of these steps as a series of callbacks, depending on the event previous to them:
menu.addEventListener('click', function() {
console.log("making pizza");
setTimeout(function() {
console.log("pizza made");
pizza.classList.remove("inactive");
pizza.addEventListener('click', function() {
console.log("eating pizza");
setTimeout(function() {
console.log("pizza eaten");
bill.classList.remove("inactive");
bill.addEventListener('click', function() {
console.log("paying bill");
setTimeout(function() {
console.log("all done");
}, 3000);
});
}, 2000);
});
}, 5000);
});
JS
We can make the previous code read like this
orderPizza()
.then(eat)
.then(pay)
.catch(badPizza);
Ok, creating the promises and executor functions was a tad messy
But the end result is that we can follow what's going on here!
Promises are a sort of contract:
Can only go from Pending to Fulfilled or Rejected (no takebacks)
Example: "I promise to return to your table"
function | description |
---|---|
new Promise(executorFn) | Creates a new Promise object with the executorFn |
promiseObject.then(onFulfilled, onRejected) | Invokes the onFulfilled (onRejected) function when the promise is fulfilled (rejected) |
promiseObject.catch(callback) | Invokes the callback function if the promise is rejected (or an error occurs) |
function executorFn(resolve, reject) {
...
if (conditionMet) {
resolve(); // Passed by the Promise object
} else {
reject(); // Passed by the Promise object
}
}
JS
You define this function and pass it into the Promise constructor
We can pass a value to resolve...
function orderExecutor(resolve, reject) {
console.log('making our pizza...');
setTimeout(function() {
resolve("Here's your pizza!");
}, 5000);
}
let orderPizza = new Promise(orderExecutor);
orderPizza.then(function (value) { console.log(value); });
JS
That value gets passed into then
The functions passed to then
can pass values to the next then
callback
function eat(value) {
return value + ", and now it's gone";
}
let orderPizza = new Promise(orderExecutor);
orderPizza.then(eat).then(function (value) { console.log(value); });
JS
You can also return other promises, which halt the execution of the next then
callback until it's resolved
function eatExecutor(resolve, reject) {
console.log('eating our pizza...');
setTimeout(resolve, 3000);
}
function eat() {
return new Promise(eatExecutor);
}
let orderPizza = new Promise(orderExecutor);
orderPizza.then(eat).then(function () { console.log('Paying the bill!'); });
JS
function orderExecutor(resolve, reject) {
console.log('Pizza ordered...');
resolve("Here's your pizza!");
}
let orderPizza = new Promise(orderExecutor);
orderPizza.then(function (value) { console.log(value); });
console.log("Waiting for my pizza!");
JS
In what order do these log statements appear in the console?
function orderExecutor(resolve, reject) { // MUST have both parameters defined
console.log('Pizza ordered...');
setTimeout(function() {
reject("Ran outta cheeese. Can you believe it?");
}, 2000);
}
let orderPizza = new Promise(orderExecutor);
orderPizza
.then(function () { console.log("Woohoo, let's eat!"); })
.catch(function (value) { console.log(value); });
JS
then
and catch
Return Promises
function executor(resolve) {
resolve('Woohoo!');
}
let myPromise = new Promise(executor);
let thenPromise = myPromise.then(console.log);
let catchPromise = thenPromise.catch(console.error);
console.log(thenPromise instanceof Promise); // true
console.log(catchPromise instanceof Promise); // true
console.log(myPromise === thenPromise); // false
console.log(myPromise === catchPromise); // false
console.log(thenPromise === catchPromise); // false
JS
then
and catch
return new Promises
then
and catch
Return Promises
function executor(resolve) {
resolve('Woohoo!');
}
function processStr(val) {
// mellow out that message a bit
return val.toLowerCase().replace('!', '');
}
let myPromise = new Promise(executor);
let thenPromise = myPromise.then(processStr);
console.log(thenPromise);
JS
processStr
returns a string, but then
turns it into a Promise that immediately resolves with the value "woohoo"
then
and catch
Return PromisesThe previous slide is equivalent to the below:
function executor(resolve) {
resolve('Woohoo!');
}
function processStr(val) {
// mellow out that message a bit
return new Promise(function(resolve) {
resolve(val.toLowerCase().replace('!', ''));
});
}
let myPromise = new Promise(executor);
let thenPromise = myPromise.then(processStr);
console.log(thenPromise);
JS
then
and catch
Return Promises
function executor(resolve) {
resolve('Woohoo!');
}
function processStr(val) {
// mellow out that message a bit
return new Promise(function(resolve) {
setTimeout(function() {
resolve(val.toLowerCase().replace('!', ''));
}, 5000);
});
}
let myPromise = new Promise(executor);
let thenPromise = myPromise.then(processStr);
console.log(thenPromise);
JS
Now, thenPromise
is "PENDING" and won't resolve until
the promise returned by processStr
resolves.
This chaining of promises is what makes the below possible
orderPizza()
.then(eat)
.then(pay)
.catch(badPizza);
let myBtn = qs('button:nth-child(1)');
while (!myBtn.clicked) {
// twiddle our thumbs
}
console.log('"Finally Been Clicked", starring Drew Barrymore');
let myBtn2 = qs('button:nth-child(2)');
while (!myBtn2.clicked) {
// twiddle our thumbs
}
console.log('"Click 2", never coming soon to a theater near you');
JS
function firstBtnClick() {
return new Promise(function (resolve) {
let myBtn = qs('button:nth-child(1)');
myBtn.addEventListener('click', resolve);
});
}
function nextBtnClick() {
return new Promise(function (resolve) {
let myBtn = qs('button:nth-child(2)');
myBtn.addEventListener('click', resolve);
});
}
firstBtnClick()
.then(() => { console.log('"Finally Been Clicked", starring Drew Barrymore'); })
.then(nextBtnClick)
.then(() => { console.log('"Click 2", never coming soon to a theater near you'); });
JS
function firstBtnClick() {
return new Promise(function (resolve) {
let myBtn = qs('button:nth-child(1)');
myBtn.addEventListener('click', resolve);
});
}
function nextBtnClick() {
return new Promise(function (resolve) {
let myBtn = qs('button:nth-child(2)');
myBtn.addEventListener('click', resolve);
});
}
await firstBtnClick();
console.log('"Finally Been Clicked", starring Drew Barrymore');
await nextBtnClick();
console.log('"Click 2", never coming soon to a theater near you');
JS
await firstBtnClick();
console.log('"Finally Been Clicked", starring Drew Barrymore');
await nextBtnClick();
console.log('"Click 2", never coming soon to a theater near you');
JS
"Syntactic sugar" that wraps a function's return in a promise
Allows code to "wait" for the thing to return.
async function sayHelloAsync(name) {
return "Hello " + name;
}
console.log(sayHelloAsync("dubs")); // Promise
let message = await sayHelloAsync("dubs");
console.log(message); // "Hello dubs"
JS
async
does the same thing to functions that then
does
await
halts execution of the code until the Promise is resolved and then
returns the resolved value of the promise
function orderExecutor(resolve, reject) { // reject not required here
console.log('making our pizza...');
setTimeout(resolve, 5000);
}
await new Promise(orderExecutor);
console.log('eating pizza!');
JS
We can pass a value to resolve...
function orderExecutor(resolve, reject) {
console.log('making our pizza...');
setTimeout(function() {
resolve("Here's your pizza!");
}, 5000);
}
let pizza = await new Promise(orderExecutor);
console.log(pizza);
JS
That value gets passed to the function passed into await
async function eat(value) {
return value + ", and now it's gone";
}
let pizza = await new Promise(orderExecutor);
let eatingResult = await eat(pizza);
console.log(eatingResult);
JS
You can also return other promises, which halt the execution of the next then
callback until it's resolved
function eatExecutor(resolve, reject) {
console.log('eating our pizza...');
setTimeout(resolve, 3000);
}
async function eat() { // don't need async here...why not?
return new Promise(eatExecutor);
}
let pizza = await new Promise(orderExecutor);
let eatingResult = await eat(pizza);
console.log('Paying the bill!');
JS
function orderExecutor(resolve, reject) {
console.log('Pizza ordered...');
setTimeout(function() {
resolve("Here's your pizza!");
}, 3000);
}
let pizza = await new Promise(orderExecutor);
console.log(pizza);
console.log('Waiting around');
JS
In what order do these log statements appear in the console?
function orderExecutor(resolve, reject) { // MUST have both parameters defined
console.log('Pizza ordered...');
setTimeout(function() {
reject("Ran outta cheeese. Can you believe it?");
}, 2000);
}
try {
let pizza = await new Promise(orderExecutor);
console.log("Woohoo, let's eat!");
} catch (error) {
console.log(error);
}
JS
For error-handling with async/await, you must use try/catch instead of .then/.catch
The catch statement will catch any errors that occur in the then block (whether it’s in a Promise or a syntax error in the function), similar to the .catch in a fetch promise chain
async
/await
For error-handling with async/await, you must use try/catch instead of .then/.catch
The catch statement will catch any errors that occur in the then block (whether it’s in a Promise or a syntax error in the function), similar to the .catch in a fetch promise chain
async
?For any function that is await
'd, but that doesn't return a promise (although it'll still work to add async
even if it does)
async function eat(value) {
return value + ", and now it's gone";
}
let pizza = await new Promise(orderExecutor);
let eatingResult = await eat(pizza); // don't need to do this. Why not?
console.log(eatingResult);
JS
For any function that that uses await
in its implementation
async function orderPizza() {
let pizza = await new Promise(orderExecutor);
return 'Done!';
}
console.log(await orderPizza());
console.log('What now?');
JS
Pizzeria: pizza.html
Some operations take an unknown amount of time or have a not insignificant chance of failure
Whether these operations succeed or fail, we still want to do something in response
Remember, Promises guarantee a response (fulfilled/resolved or rejected)
fetch
Allows us to use JavaScript to request resources from servers connected to the internet
fetch("http://www.weather.com")
Can think of it as replicating the behavior of our browser address bar
fetch
returns a Promise!
fetch
Allows us to use JavaScript to request resources from servers connected to the internet
fetch("http://www.weather.com")
.then(checkStatus) // check out HTTP status code
.then(getText) // get the content from the response
.then(process) // do something with the response content
.catch(handleError); // do something on failure
JS
Or
try {
let resp = await fetch("http://www.weather.com");
checkStatus(resp); // check out HTTP status code
let text = await getText(resp); // get the content from the response
process(text) // do something with the response content
} catch (error) {
handleError(error);
}
JS
Get HTML: html.html
Especially if you're watching a recording, write your question on PollEverywhere and I'll answer them at the start of next lecture.
Either on your phone or computer, go to PollEv.com/robcse