Const vs. let when using async

I was curious about this. All the exercises uses let instead of const. Is there a specific reason for this. Was it just the authors preference? Can you instead use const until you need to use let?

async function usingTryCatch() {
 try {
   let resolveValue = await asyncFunction('thing that will fail');
   let secondValue = await secondAsyncFunction(resolveValue);
 } catch (err) {
   // Catches any errors in the try block
   console.log(err);
 }
}

usingTryCatch();

async function usingPromiseCatch() {
   let resolveValue = await asyncFunction('thing that will fail');
}

let rejectedPromise = usingPromiseCatch();
rejectedPromise.catch((rejectValue) => {
console.log(rejectValue);
})

No need to, really. let gives block scope, which is more than adequate.

Unless I’m mistaken const and let both have block scope. The difference is that a variable declared with the keyword const can’t be reassigned. The only reason to use let in the above examples would be if you need to reassign a different value to the variable in question later in the function. I went back through the exercises on async functions, and replaced let with const in all cases with no issues.

1 Like

See, I been using const on all the exercises without error. My thoughts on this was that const would lock the value in, which I would assume would be desirable in most cases until the time arrives that you need that variable to be mutable which then you would use let. Is that something to be of concern, or just my opinion and preference?

1 Like

Similar to CSS, where we use the least specificity possible on our selectors, in JS we are only concerned with scope, for the most part. In such a small block do we need to protect the integrity of a variable? Not really. All we want is for it to not leak into the scope chain.

My thinking is that we need only use const when it serves a real purpose, such as protecting a data structure or preserving a constant value. In such a confined space as the small blocks above, it is doing neither of those.

3 Likes

My thinking is kinda the opposite. That we should preserve resources by using const whenever possible inside of a block. Since the computer knows it can’t be reassigned, it can optimize the memory allocated. Is that not the case?
From the Codecademy course: https://www.codecademy.com/paths/web-development/tracks/getting-started-with-javascript/modules/learn-javascript-introduction/lessons/variables/exercises/review-variables

Variables

Review Variables

Nice work! This lesson introduced you to variables, a powerful concept you will use in all your future programming endeavors.

Let’s review what we learned:

  • Variables hold reusable data in a program and associate it with a name.
  • Variables are stored in memory.
  • The var keyword is used in pre-ES6 versions of JS.
  • let is the preferred way to declare a variable when it can be reassigned, and const is the preferred way to declare a variable with a constant value.
  • Variables that have not been initialized store the primitive data type undefined .
  • Mathematical assignment operators make it easy to calculate a new value and assign it to the same variable.
  • The + operator is used to concatenate strings including string values held in variables
  • In ES6, template literals use backticks ``` and ${} to interpolate values into a string.
  • The typeof keyword returns the data type (as a string) of a value.

Once we exit the function the variables are garbage collected. There is nothing to preserve. const doesn’t use any less resources than let. I like to think of const as applying to a larger scope, such as the entire program in global scope, or in a setting where there may be volatility such as a namespace that imports from another namespace.

I ran into another lesson where I saw how using const and let can have unexpected results. Originally, everything in this code at the top with my vars was const except let opendoor1, opendoor2, opendoor3.

It worked for about 50 steps into a 70 step project. Then things just stopped working and for a while could not figure out why. When I went back and changed the other vars up top to let, things began working again.

let doorImage1 = document.getElementById('door1');
let doorImage2 = document.getElementById('door2');
let doorImage3 = document.getElementById('door3');
let startButton = document.getElementById('start');

const botDoorPath = 'https://s3.amazonaws.com/codecademy-content/projects/chore-door/images/robot.svg';
const beachDoorPath = 'https://s3.amazonaws.com/codecademy-content/projects/chore-door/images/beach.svg';
const spaceDoorPath = 'https://s3.amazonaws.com/codecademy-content/projects/chore-door/images/space.svg';
const closedDoorPath = 'https://s3.amazonaws.com/codecademy-content/projects/chore-door/images/closed_door.svg';

let numClosedDoors = 3;
let currentlyPlaying = true;

let openDoor1;
let openDoor2;
let openDoor3;

const isBot = (door) => {
  return door.src === botDoorPath ? true : false;  
}

const isClicked = (door) => {
  return door.src === closedDoorPath ? false : true;
}

const playDoor = (door) => {
  numClosedDoors--;
  
  if (numClosedDoors === 0) {
  	gameOver('win');
  } else if (isBot(door)) {
    gameOver('lose');
  }
}

const randomChoreDoorGenerator = () => {
  let choreDoor = Math.floor(Math.random() * numClosedDoors);
  
  if (choreDoor === 0) {
    openDoor1 = botDoorPath;
    openDoor2 = beachDoorPath;
    openDoor3 = spaceDoorPath;    
  } else if (choreDoor === 1) {
    openDoor2 = botDoorPath;
    openDoor3 = beachDoorPath;
    openDoor1 = spaceDoorPath;
  } else if (choreDoor === 2) {
    openDoor3 = botDoorPath;
    openDoor1 = beachDoorPath;
    openDoor2 = spaceDoorPath;
  } else {
    console.log('ERROR! - if/else statement in randomChoreDoorGenerator function.');
  }
}

doorImage1.onclick = () => {
  if (!isClicked(doorImage1) && currentlyPlaying) {
    doorImage1.src = openDoor1;
  	playDoor(doorImage1);
  }
}

doorImage2.onclick = () => {
  if (!isClicked(doorImage2) && currentlyPlaying) {
    doorImage2.src = openDoor2;
  	playDoor(doorImage2);
  }
}

doorImage3.onclick = () => {
  if (!isClicked(doorImage3) && currentlyPlaying) {
    doorImage3.src = openDoor3;
  	playDoor(doorImage3);
  }
}

startButton.onclick = () => {
  if (!currentlyPlaying) startRound();
}

const startRound = () => {
  numClosedDoors = 3;
  currentlyPlaying = true;
  doorImage1.src = closedDoorPath;
  doorImage2.src = closedDoorPath;
  doorImage3.src = closedDoorPath;
  startButton.innerHTML = 'Good Luck!';
  randomChoreDoorGenerator();
}

const gameOver = (status) => {
  if (status === 'win') {
    startButton.innerHTML = "You win! Play again?";
  } else {
    startButton.innerHTML = "Game over! Play again?";
  }
  currentlyPlaying = false;  
}

startRound();```

Check out these links:



3 Likes

I understand from C style languages that you always go with const keyword first. My point in that post is that I did so, but later on had to use let because the unexpected behavior was due to locking in those vars. As for the var keyword, I haven’t gotten that far but generally do so on arrays that have mixed data types and those types will not be static.

All very good arguments in the grand scheme of things. The most significant point I found in all that is that we should not be re-using variables to represent different objects. Once a variable is declared as a certain concept and type, it should continue to do so throughout its usage session.

An example of re-usage that has some Ruby learners confused is in the Histogram exercise where frequencies is first a hash (similar to JS object) and then transformed into a sorted array of arrays. const in JS would prevent this from happening, and thus avoid confusion for the reader.

I get that declaration keywords are signals, but we can get all bent around this with rigidity in our thinking. Not a bad thing, per se, but still, we need some flexibility in our planning or it stymies creativity and exploration.

In the end, it boils down to how far-reaching a variable is on the larger scale. In tiny methods that are essentially one and done, the scope vanishes upon exit. So long as our variables are not leaking out, we can be happy. var, let and const all serve that purpose to one degree or another.

Bottom line, go with what suits you and we don’t have to make this into an argument.

1 Like

These variables could, and probably should be declared with const instead of let. I just looked back at the Chore Door project, and noticed in the hint that they use let, but these variables are being assigned specific HTML element references that we will definitely not want to change. Works either way, but I believe const is more appropriate. Just my opinion. Happy coding!

1 Like

This is the source of the exercise (the way Codecademy did it). I could likely go back and see if changing those vars you posted back to const and see if it works. Those were originally declared as const in my code. By the time I finished that project I was so burnt on it from debugging that I left it alone after getting it to work.

The source code IMO, the way it was done, was either due to preference, or so the viewer could easily discern vars from functions, or both. However, again I agree (personally) that vars should be locked in unless they need to mutate. That’s just my preference and background.

EDIT: I changed the vars up top from let to const and it indeed did work. Not sure now what happened. Probably something to do with the project being incomplete is my guess and how behavior changes when it became complete.

let door1 = document.getElementById('door1');
let door2 = document.getElementById('door2');
let door3 = document.getElementById('door3');
let startButton = document.getElementById('start');

let botDoorPath = "https://s3.amazonaws.com/codecademy-content/projects/chore-door/images/robot.svg";
let beachDoorPath = "https://s3.amazonaws.com/codecademy-content/projects/chore-door/images/beach.svg";
let spaceDoorPath = "https://s3.amazonaws.com/codecademy-content/projects/chore-door/images/space.svg";
let closedDoorPath = "https://s3.amazonaws.com/codecademy-content/projects/chore-door/images/closed_door.svg"

let numClosedDoors = 3;
let openDoor1;
let openDoor2;
let openDoor3;
let currentlyPlaying = true;
let score = 0;
let highScore = 0;
let currentStreak = document.getElementById('score-number');
let bestStreak = document.getElementById('high-score-number');

currentStreak.innerHTML = score;
bestStreak.innerHTML = highScore;

const isClicked = (door) => {
  if (door.src == closedDoorPath) {
    return false;
  } else {
    return true;
  }
}

const isBot = (door) => {
  if (door.src === botDoorPath) {
    return true;
  } else {
    return false;
  }
}

const playDoor = (door) => {
  numClosedDoors--;
  if (numClosedDoors === 0) {
    gameOver('win');
  } else if (isBot(door)) {
    gameOver('lose');
  }
}

// MVP - If/Else Generator (3 possible combinations)
// const randomChoreDoorGenerator = () => {
//   choreDoor = Math.floor(Math.random() * numClosedDoors);
//   if (choreDoor === 0) {
//     openDoor1 = botDoorPath;
//     openDoor2 = beachDoorPath;
//     openDoor3 = spaceDoorPath;
//   } else if (choreDoor === 1) {
//     openDoor2 = botDoorPath;
//     openDoor1 = beachDoorPath;
//     openDoor3 = spaceDoorPath;
//   } else {
//     openDoor3 = botDoorPath;
//     openDoor1 = beachDoorPath;
//     openDoor2 = spaceDoorPath;
//   }
// }

//Next Steps - Switch Statement Version (6 possible combinations)
const randomChoreDoorGenerator = () => {
  choreDoor = Math.floor(Math.random() * 6);
  switch (choreDoor) {
    case 0:
      openDoor1 = botDoorPath;
      openDoor2 = beachDoorPath;
      openDoor3 = spaceDoorPath;
      break;
    case 1:
      openDoor1 = botDoorPath;
      openDoor2 = spaceDoorPath;
      openDoor3 = beachDoorPath;
      break;
    case 2:
      openDoor2 = botDoorPath;
      openDoor1 = beachDoorPath;
      openDoor3 = spaceDoorPath;
      break;
    case 3:
      openDoor2 = botDoorPath;
      openDoor1 = spaceDoorPath;
      openDoor3 = beachDoorPath;
      break;
    case 4:
      openDoor3 = botDoorPath;
      openDoor1 = beachDoorPath;
      openDoor2 = spaceDoorPath;
      break;
    case 5:
      openDoor3 = botDoorPath;
      openDoor1 = spaceDoorPath;
      openDoor2 = beachDoorPath;
      break;
  }
}

door1.onclick = () => {
  if(currentlyPlaying && !isClicked(door1)) {
    door1.src = openDoor1;
    playDoor(door1);
  }
}

door2.onclick = () => {
  if(currentlyPlaying && !isClicked(door2)) {
    door2.src = openDoor2;
    playDoor(door2);
  }
}

door3.onclick = () => {
  if(currentlyPlaying && !isClicked(door3)) {
    door3.src = openDoor3;
    playDoor(door3);
  }
}

startButton.onclick = () => {
    startRound();
}

const startRound = () => {
  // Reset all the doors to be closed
  door1.src = closedDoorPath;
  door2.src = closedDoorPath;
  door3.src = closedDoorPath;
  numClosedDoors = 3;
  currentlyPlaying = true;
  startButton.innerHTML = 'Good luck!';
  randomChoreDoorGenerator();
}

const gameOver = (str) => {
  if(str === 'win') {
    startButton.innerHTML = 'You win! Play again?';
    getYourScore();
  } else {
    startButton.innerHTML = "Game over! Play again?"
    score = 0;
    currentStreak.innerHTML = score;
  }
  currentlyPlaying = false;
}

const getYourScore = () => {
  score++;
  currentStreak.innerHTML = score;
  if (score > highScore) {
    highScore = score;
    bestStreak.innerHTML = highScore;
  }
}


startRound();
1 Like

Here’s my declarations for comparison if you like:

const doorImage1 = document.getElementById('door1');
const doorImage2 = document.getElementById('door2');
const doorImage3 = document.getElementById('door3');
const statWins = document.getElementById('wins');
const statLosses = document.getElementById('losses');
const statCurrentStreak = document.getElementById('current-streak');
const statLongestStreak = document.getElementById('longest-streak');
const botDoorPath = "https://s3.amazonaws.com/codecademy-content/projects/chore-door/images/robot.svg";
const beachDoorPath = "https://s3.amazonaws.com/codecademy-content/projects/chore-door/images/beach.svg";
const spaceDoorPath = "https://s3.amazonaws.com/codecademy-content/projects/chore-door/images/space.svg";
let numClosedDoors = 3;
let openDoor1, openDoor2, openDoor3;
let wins = 0, losses = 0, streak = 0, longestStreak = 0;
const closedDoorPath = "https://s3.amazonaws.com/codecademy-content/projects/chore-door/images/closed_door.svg";
const startButton = document.getElementById('start');
let currentlyPlaying = true;

I like white-spacing. I assume you don’t. I also prefer to group my global vars together if they are similar. For the most part you do, except for startButton and closedDoorPath. Just my preference.