- Synchronous execution 同步执行,按照代码顺序
- Asynchronous execution 异步执行,加载慢的放到callback queue,比如调用第三方api
- Pending => The initial state - not completed yet
- Fulfilled => Successfully completed with a resolved value
- Rejected => Failed operation - the reason is usually an Error of some kind
JavaScript Callbacks
- 用setTimeout(functionName, 3000);来延迟加载
- Function写在setTimeout里, setTimeout(function(){内容},3000);
- WebAPI 用browser来帮忙处理, 除了settimeout,还有比如addEventListener()
- 避免callback hell, Promise解决callback hell, assync await解决清晰的代码逻辑
setTimeout(()=>{
console.log("hello");
}, 2000)
function getData(name, callback){
setTimeout(()=>{
callback({name: name, age: Math.floor(Math.random() * 30), major:"CS"})
}, 2000);
}
function getMovies(age, callback){
if(age < 12){
setTimeout(()=>{
callback("Kids");
},1500);
}else if(age < 18){
setTimeout(()=>{
callback("Teens");
},1500);
}else{
setTimeout(()=>{
callback("Adult");
},1500);
}
}
console.log("start");
getData("Daniel", (obj)=>{
console.log(obj);
getMovies(obj.age, (str)=>{
console.log(str);
});
});
console.log("End");
JavaScript Promise
Promise是一个object,所以用new,里面有两个参数, resolve和reject 用法结构如下,比Callbacks更简洁
a()
.then(function(){})
.then(function(){})
.then(function(){})
Example
function getData(name){
if(name == "Daniel"){
return new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve({name: name, age: Math.floor(Math.random() * 30), major:"CS"})
}, 2000);
});
}else{
return new Promise((resolve, reject)=>{
setTimeout(()=>{
reject(new Error("Not allowed to access data."))
}, 2000);
});
}
}
function getMovies(age){
if(age < 12){
return new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve({text: "Kids"});
},1500);
});
}else if(age < 18){
return new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve({text: "Teens"});
}, 1500);
});
}else{
return new Promise((resolve, reject)=> {
setTimeout(()=>{
resolve({text: "Adults"});
},1500);
});
}
}
getData("Daniel")
.then((obj) => {
console.log(obj);
return getMovies(obj.age);
})
.then((meg) =>{
console.log(meg.text);
})
.catch((e) => {
console.log(e);
});
Example 2
let sentToAirport = true;
let p = new Promise(function(resolve, reject){
if(sentToAirport){
console.log("sent to airport");
resolve();
}else{
console.log("cannot send to airport");
reject();
}
});
p
.then(function(){console.log("promise resolved")})
.catch(function(){console.log("promise rejected")});
let sentToAirport = true;
let p = new Promise(function(resolve, reject){
if(sentToAirport){
resolve("from resolve(): send to airport"); //返回任何值, 类似return
}else{
reject("from reject(): cannot to airport");
}
});
p
.then(function(message){console.log(message)}) //resolve的值
.catch(function(message){console.log(message)}); //reject的值
let f = fetch("https://jsonplaceholder.typicode.com/users");
f
.then(function(userData){
return userData.json(); //原始数据转换成json数据
})
.then(function(jsonData){
console.log(jsonData);
});
Constructing a Promise Object
const inventory = {
sunglasses: 0,
pants: 1088,
bags: 1344
};
// Write your code below:
const myExecutor = (resolve, reject) =>{
if(inventory.sunglasses > 0){
resolve('Sunglasses order processed.');
}
else{
reject('That item is sold out.');
}
}
const orderSunglasses = () => new Promise(myExecutor);
const orderPromise = orderSunglasses();
console.log(orderPromise);
The Node setTimeout() Function
console.log("This is the first line of code in app.js.");
// Keep the line above as the first line of code
// Write your code here:
const usingSTO = () => {
console.log("Hello");
}
setTimeout(usingSTO, 3000);
// Keep the line below as the last line of code:
console.log("This is the last line of code in app.js.");
Success and Failure Callback Functions
library.js
const inventory = {
sunglasses: 1900,
pants: 1088,
bags: 1344
};
const checkInventory = (order) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
let inStock = order.every(item => inventory[item[0]] >= item[1]);
if (inStock) {
resolve(`Thank you. Your order was successful.`);
} else {
reject(`We're sorry. Your order could not be completed because some items are sold out.`);
}
}, 1000);
})
};
module.exports = { checkInventory };
app.js
const {checkInventory} = require('./library.js');
const order = [['sunglasses', 1], ['bags', 2]];
// Write your code below:
const handleSuccess = (value) => {
console.log(value);
}
const handleFailure = (value) =>{
console.log(value);
}
checkInventory(order)
.then(handleSuccess, handleFailure);
Using catch() with Promises
library.js
const inventory = {
sunglasses: 0,
pants: 1088,
bags: 1344
};
const checkInventory = (order) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
let inStock = order.every(item => inventory[item[0]] >= item[1]);
if (inStock) {
resolve(`Thank you. Your order was successful.`);
} else {
reject(`We're sorry. Your order could not be completed because some items are sold out.`);
}
}, 1000);
});
};
module.exports = {checkInventory};
app.js
const {checkInventory} = require('./library.js');
const order = [['sunglasses', 1], ['bags', 2]];
const handleSuccess = (resolvedValue) => {
console.log(resolvedValue);
};
const handleFailure = (rejectReason) => {
console.log(rejectReason);
};
// Write your code below:
checkInventory(order)
.then(handleSuccess)
.catch(handleFailure);
Chaining Multiple Promises
library.js
const store = {
sunglasses: {
inventory: 817,
cost: 9.99
},
pants: {
inventory: 236,
cost: 7.99
},
bags: {
inventory: 17,
cost: 12.99
}
};
const checkInventory = (order) => {
return new Promise ((resolve, reject) => {
setTimeout(()=> {
const itemsArr = order.items;
let inStock = itemsArr.every(item => store[item[0]].inventory >= item[1]);
if (inStock){
let total = 0;
itemsArr.forEach(item => {
total += item[1] * store[item[0]].cost
});
console.log(`All of the items are in stock. The total cost of the order is ${total}.`);
resolve([order, total]);
} else {
reject(`The order could not be completed because some items are sold out.`);
}
}, generateRandomDelay());
});
};
const processPayment = (responseArray) => {
const order = responseArray[0];
const total = responseArray[1];
return new Promise ((resolve, reject) => {
setTimeout(()=> {
let hasEnoughMoney = order.giftcardBalance >= total;
// For simplicity we've omited a lot of functionality
// If we were making more realistic code, we would want to update the giftcardBalance and the inventory
if (hasEnoughMoney) {
console.log(`Payment processed with giftcard. Generating shipping label.`);
let trackingNum = generateTrackingNumber();
resolve([order, trackingNum]);
} else {
reject(`Cannot process order: giftcard balance was insufficient.`);
}
}, generateRandomDelay());
});
};
const shipOrder = (responseArray) => {
const order = responseArray[0];
const trackingNum = responseArray[1];
return new Promise ((resolve, reject) => {
setTimeout(()=> {
resolve(`The order has been shipped. The tracking number is: ${trackingNum}.`);
}, generateRandomDelay());
});
};
// This function generates a random number to serve as a "tracking number" on the shipping label. In real life this wouldn't be a random number
function generateTrackingNumber() {
return Math.floor(Math.random() * 1000000);
}
// This function generates a random number to serve as delay in a setTimeout() since real asynchrnous operations take variable amounts of time
function generateRandomDelay() {
return Math.floor(Math.random() * 2000);
}
module.exports = {checkInventory, processPayment, shipOrder};
app.js
const {checkInventory, processPayment, shipOrder} = require('./library.js');
const order = {
items: [['sunglasses', 1], ['bags', 2]],
giftcardBalance: 79.82
};
checkInventory(order)
.then((resolvedValueArray) => {
// Write the correct return statement here:
return processPayment(resolvedValueArray);
})
.then((resolvedValueArray) => {
// Write the correct return statement here:
return shipOrder(resolvedValueArray);
})
.then((successMessage) => {
console.log(successMessage);
})
.catch((errorMessage) => {
console.log(errorMessage);
});
Avoiding Common Mistakes (Best practice)
const {checkInventory, processPayment, shipOrder} = require('./library.js');
const order = {
items: [['sunglasses', 1], ['bags', 2]],
giftcardBalance: 79.82
};
// Refactor the code below:
checkInventory(order)
.then((resolvedValueArray) => {
return processPayment(resolvedValueArray);
})
.then((resolvedValueArray) => {
return shipOrder(resolvedValueArray);
})
.then((successMessage) => {
console.log(successMessage);
});
Using Promise.all()
app.js
const {checkAvailability} = require('./library.js');
const onFulfill = (itemsArray) => {
console.log(`Items checked: ${itemsArray}`);
console.log(`Every item was available from the distributor. Placing order now.`);
};
const onReject = (rejectionReason) => {
console.log(rejectionReason);
};
// Write your code below:
const checkSunglasses = checkAvailability('sunglasses', 'Favorite Supply Co.');
const checkPants = checkAvailability('pants', 'Favorite Supply Co.');
const checkBags = checkAvailability('bags', 'Favorite Supply Co.');
const promiseArray = [checkSunglasses, checkPants, checkBags];
Promise.all(promiseArray)
.then(onFulfill)
.catch(onReject);
library.js
const checkAvailability = (itemName, distributorName) => {
console.log(`Checking availability of ${itemName} at ${distributorName}...`);
return new Promise((resolve, reject) => {
setTimeout(() => {
if (restockSuccess()) {
console.log(`${itemName} are in stock at ${distributorName}`)
resolve(itemName);
} else {
reject(`Error: ${itemName} is unavailable from ${distributorName} at this time.`);
}
}, 1000);
});
};
module.exports = { checkAvailability };
// This is a function that returns true 80% of the time
// We're using it to simulate a request to the distributor being successful this often
function restockSuccess() {
return (Math.random() > .2);
}
Async Await
总结:
- Async Await 更贴近同步执行代码
- Async Await的概念是由Promise基础上演变
- Async function会返回Promise object
- Await 关键字只能在Async function里使用
function sendRequest(){
return new Promise(function(resolve, reject){
setTimeout(function(){
resolve("DanielHuang");
//reject("Request reject dur to server error");
},2000);
});
}
async function getUsername(){
try{
let username = await sendRequest();
//let username = await fetch("https://jsonplaceholder.typicode.com/users");
console.log(username);
}catch(message){
console.log(`Error: ${message}`);
}
}
getUsername();
The async Keyword
function withConstructor(num){
return new Promise((resolve, reject) => {
if (num === 0){
resolve('zero');
} else {
resolve('not zero');
}
});
}
withConstructor(0)
.then((resolveValue) => {
console.log(` withConstructor(0) returned a promise which resolved to: ${resolveValue}.`);
});
// Write your code below:
async function withAsync(num){
if (num === 0){
return('zero');
} else {
return('not zero');
}
}
// Leave this commented out until step 3:
withAsync(100)
.then((resolveValue) => {
console.log(` withAsync(100) returned a promise which resolved to: ${resolveValue}.`);
})
The await Operator
const brainstormDinner = require('./library.js');
// Native promise version:
function nativePromiseDinner() {
brainstormDinner().then((meal) => {
console.log(`I'm going to make ${meal} for dinner.`);
});
}
// async/await version:
async function announceDinner() {
// Write your code below:
let meal = await brainstormDinner();
console.log(`I'm going to make ${meal} for dinner.`);
}
announceDinner();
Handling Dependent Promises
app.js
const {shopForBeans, soakTheBeans, cookTheBeans} = require('./library.js');
// Write your code below:
async function makeBeans(){
let type = await shopForBeans();
let isSoft = await soakTheBeans(type);
let dinner = await cookTheBeans(isSoft);
console.log(dinner);
}
makeBeans();
library.js
/*
This is the shopForBeans function from the last exercise
*/
const shopForBeans = () => {
return new Promise((resolve, reject) => {
const beanTypes = ['kidney', 'fava', 'pinto', 'black', 'garbanzo'];
setTimeout(()=>{
let randomIndex = Math.floor(Math.random() * 5);
let beanType = beanTypes[randomIndex];
console.log(`I bought ${beanType} beans because they were on sale.`);
resolve(beanType);
}, 1000)
})
}
let soakTheBeans = (beanType) => {
return new Promise((resolve, reject) => {
console.log('Time to soak the beans.');
setTimeout(()=>{
console.log(`... The ${beanType} beans are softened.`);
resolve(true);
}, 1000);
});
}
let cookTheBeans = (isSoftened) => {
return new Promise((resolve, reject) => {
console.log('Time to cook the beans.');
setTimeout(()=>{
if (isSoftened) {
console.log('... The beans are cooked!');
resolve('\n\nDinner is served!');
}
}, 1000);
});
}
module.exports = {shopForBeans, soakTheBeans, cookTheBeans};
Handling Errors
app.js
const cookBeanSouffle = require('./library.js');
// Write your code below:
async function hostDinnerParty(){
try{
let resolveValue = await cookBeanSouffle();
console.log(resolveValue + ' is served!')
}
catch(error){
console.log(error);
console.log('Ordering a pizza!');
}
}
hostDinnerParty();
libray.js
// This function returns true 50% of the time.
let randomSuccess = () => {
let num = Math.random();
if (num < .5 ){
return true;
} else {
return false;
}
};
// This function returns a promise that resolves half of the time and rejects half of the time
let cookBeanSouffle = () => {
return new Promise((resolve, reject) => {
console.log('Fingers crossed... Putting the Bean Souffle in the oven');
setTimeout(()=>{
let success = randomSuccess();
if(success){
resolve('Bean Souffle');
} else {
reject('Dinner is ruined!');
}
}, 1000);
});
};
module.exports = cookBeanSouffle;
Handling Independent Promises
app.js
let {cookBeans, steamBroccoli, cookRice, bakeChicken} = require('./library.js');
// Write your code below:
async function serveDinner(){
let vegetablePromise = steamBroccoli();
let starchPromise = cookRice();
let proteinPromise = bakeChicken();
let sidePromise = cookBeans();
console.log(`Dinner is served. We're having ${await vegetablePromise}, ${await starchPromise}, ${await proteinPromise}, and ${await sidePromise}.`);
}
serveDinner();
library.js
let cookBeans = () => {
return new Promise ((resolve, reject) => {
setTimeout(()=>{
resolve('beans');
}, 1000);
});
}
let steamBroccoli = () => {
return new Promise ((resolve, reject) => {
setTimeout(()=>{
resolve('broccoli');
}, 1000);
});
}
let cookRice = () => {
return new Promise ((resolve, reject) => {
setTimeout(()=>{
resolve('rice');
}, 1000);
});
}
let bakeChicken = () => {
return new Promise ((resolve, reject) => {
setTimeout(()=>{
resolve('chicken');
}, 1000);
});
}
module.exports = {cookBeans, steamBroccoli, cookRice, bakeChicken};
Await Promise.all()
let {cookBeans, steamBroccoli, cookRice, bakeChicken} = require('./library.js');
// Write your code below:
async function serveDinnerAgain(){
let foodArray = await Promise.all([steamBroccoli(),cookRice(),bakeChicken(),cookBeans()]);
console.log(`Dinner is served. We're having ${foodArray[0]}, ${foodArray[1]}, ${foodArray[2]}, and ${foodArray[3]}.`);
/*
let vegetable = foodArray[0];
let starch = foodArray[1];
let protein = foodArray[2];
let side = foodArray[3];
console.log(`Dinner is served. We're having ${vegetable}, ${starch}, ${protein}, and ${side}.`);
*/
}
serveDinnerAgain();
Review
async...await
is syntactic sugar built on native JavaScript promises and generators.- We declare an async function with the keyword
async
. - Inside an
async
function we use the await operator to pause execution of our function until an asynchronous action completes and the awaited promise is no longer pending . await
returns the resolved value of the awaited promise.- We can write multiple
await
statements to produce code that reads like synchronous code. - We use
try...catch
statements within ourasync
functions for error handling. - We should still take advantage of concurrency by writing
async
functions that allow asynchronous actions to happen in concurrently whenever possible.