JavaScript Notes 6 Classes

BY Guanqiao Huang

Posted by HUANG on January 1, 0201
  • 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

  1. 用setTimeout(functionName, 3000);来延迟加载
  2. Function写在setTimeout里, setTimeout(function(){内容},3000);
  3. WebAPI 用browser来帮忙处理, 除了settimeout,还有比如addEventListener()
  4. 避免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

总结:

  1. Async Await 更贴近同步执行代码
  2. Async Await的概念是由Promise基础上演变
  3. Async function会返回Promise object
  4. 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 our async 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.