Categories
JavaScript Basics

Async Iteration with JavaScript

Asynchronous code is a very important part of JavaScript. We need to write lots of asynchronous code since JavaScript is a single-threaded language. If we run everything line by line, then code that takes longer to run will hold up the program, causing it to freeze.

To write asynchronous code easily, JavaScript has promises which are chainable and can be run in sequence without nesting.

ES2017 introduced the async and await syntax for chaining promises, which makes everything easier. However, there was still no way to run promises sequentially by iterating them in sequence. This means that running lots of promises in a sequence is still a problem that has no solution yet.

Fortunately, in ES2018, we finally have the for-await-of loop that we can use with async functions that were introduced in ES2017. It works with any iterable objects like the synchronous for...of loop. This means that we can iterate through objects like Maps, Sets, NodeLists, and the arguments object with it.

Also, it can iterate through any object with the Symbol.iterator method which returns a generator to let us do the iteration.

for-await-of Loop

We can use the for-await-of loop as follows:

let promises = [];
for (let i = 1; i <= 10; i++) {
  promises.push(new Promise((resolve) => {
    setTimeout(() => resolve(i), 1000);
  }));
}

(async () => {
  for await (let p of promises) {
    const val = await p;
    console.log(val);
  }
})();

In the example above, we added 10 promises by defining them in the for loop and then pushing them to the promises array. Then we run the promises one at a time by defining an async function and then use the for-await-of loop to loop through each promise and run them one at a time.

The await in the for-await-of loop will get us the resolved value from the promise and the console.log will log the resolved value.

Like any other async functions, it can only return promises.

The syntax of the for-await-of loop is the same as any other for...of loop. The let p is the variable declaration and promises is the promises array that we’re iterating through.

The code above works like Promise.all , the code is run in parallel, so we see 1 to 10 after 1 second.

Async Iterables

Alternatively, we can define our own asynchronous iterable object if we define an object with the Symbol.asyncIterator method. It’s a special method that returns a generator lets us iterate through it with the for-await-of loop.

For example, we can write:

let asyncIterable = {
  [Symbol.asyncIterator]() {
    return {
      i: 1,
      next() {
        if (this.i <= 10) {
          return new Promise((resolve) => {
            setTimeout(() => resolve({
              value: this.i++,
              done: false
            }), 1000);
          });
        }

        return Promise.resolve({
          done: true
        });
      }
    };
  }
};

(async () => {
  for await (let p of asyncIterable) {
    const val = await p;
    console.log(val);
  }
})();

The code above will return a generator which returns a new promise as the for-await-of loop runs.

In the Symbol.asyncIterator method, we have a next function, which is required if we want to make an asynchronous iterable object. Also, we have the i property to keep track of what we iterated through. ‘

In the promise that we return, we have the setTimeout with a callback function that resolves to an object with the value we want to resolve, and the property done . The done property is false if the iterator should keep on returning new values for the for-await-of loop and true otherwise.

Async Generator

We can make the code shorter with the yield keyword to make a generator function to return a generator. Generators are another kind of iterable object which can be used with the for-await-of loop.

For example, we can write:

async function* asyncGenerator() {
  for (let i = 1; i <= 10; i++) {
    yield i;
  }
}

(async () => {
  for await (let p of asyncGenerator()) {
    const val = await p;
    console.log(val);
  }
})();

The keyword function* denotes that our function only returns a generator. async means that the generator runs asynchronously. Inside the asyncGenerator function, we have the yield keyword. The yield keyword gets us the next item from the generator as we loop through the generator with the for-await-of loop.

The yield keyword only works with top-level code. It doesn’t work inside callback functions.

If we run the code above, we should get 1 to 10 outputted.

If we write something like:

async function* asyncGenerator() {
  for (let i = 1; i <= 10; i++) {
    setTimeout(() => {
      yield i;
    }, 1000);
  }
}

We’ll get a SyntaxError .

An object can be made iterable with if we define a Symbol.asyncIterator method which is set to a generator function.

For example, we can write:

(async () => {
  const iterableObj = {
    [Symbol.asyncIterator]: async function*() {
      for (let i = 1; i <= 10; i++) {
        yield i;
      }
    }
  }

  for await (let val of iterableObj) {
    console.log(val);
  }
})();

Then we get 1 to 10 logged in the console.log output.

It works like the asyncIterable object we defined above, except that the code is much shorter. Also, we can’t use the yield keyword on callbacks so we’ve to write it like what we have above in that case.

Finally, we can write the following to loop through promises directly:

(async () => {

  for await (let i of Array.from({
    length: 10
  }, ((v, i) => i))) {
    const val = await new Promise((resolve) => {
      setTimeout(() => resolve(i), 1000)
    })
    console.log(val);
  }
})();

The await keyword actually waits for each promise to resolve until running the next one, so we get each number showing up after 1 second when we run the code.

Asynchronous iteration solves the promise of running many promises sequentially. This feature is available in ES2018 or later with the introduction of the for-await-of loop and asynchronous iterators and generators. With them, we solved the issue of iterating through asynchronous code.

Categories
JavaScript Basics

Removing Duplicate Objects in a JavaScript Array

Removing duplicate objects in an array can take some effort.

It’s not as simple as removing duplicate primitive values from an array.

In this article, we’ll look at how to remove duplicate objects from an array.

Eliminating Duplicates Values from Arrays

Removing duplicate values is simple.

We just convert it to a set and then spread it back to an array.

For instance, we can write:

const arr = ['foo', 'bar', 'foo'];
const uniqueArr = [...new Set(arr)];

Then we get [“foo”, “bar”] as the value of uniqueArr .

This won’t work with objects since only objects with the same reference are considered the same.

Create New Array without Duplicates

One way to remove duplicates is to create a new array without the duplicate entries.

For example, if we have the following array:

const persons = [{
    firstName: 'jane',
    lastName: 'snith',
    age: 20
  },
  {
    firstName: 'bob',
    lastName: 'jones',
    age: 33,
  },
  {
    firstName: 'jane',
    lastName: 'snith',
    age: 20
  },
];

Then we can check each object for existence in the array with the unique entries.

If it doesn’t already exist, we put it into the array with unique values.

To do that, we can write the following code:

const uniquePersons = [];

for (const p of persons) {
  if (!contains(uniquePersons, p)) {
    uniquePersons.push(p);
  }
}

function contains(arr, person) {
  return arr.find(
    (a) => a.firstName === person.firstName && a.lastName === person.lastName && a.age === person.age);
}

We have the uniquePersons array to hold the array entries with the unique entries from the persons array.

The contains function returns if the item exists in the arr array.

person is the object from persons we wan to check.

We call arr.find with the condition that we want to return to check for the properties of person to determine existence.

In the for-of loop, we only call push on uniquePersons to add items from persons that doesn’t already exist.

In the end, uniquePersons is:

[
  {
    "firstName": "jane",
    "lastName": "snith",
    "age": 20
  },
  {
    "firstName": "bob",
    "lastName": "jones",
    "age": 33
  }
]

Using filter()

Another way to remove duplicate objects from an array is to use the filter method to check if the object is the first instance of the object.

To do that, we can write:

const uniquePersons = persons.filter(
  (m, index, ms) => getFirstIndex(ms, m) === index);

function getFirstIndex(arr, person) {
  return arr.findIndex(
    (a) => a.firstName === person.firstName && a.lastName === person.lastName && a.age === person.age);
}

given that we have

const persons = [{
    firstName: 'jane',
    lastName: 'snith',
    age: 20
  },
  {
    firstName: 'bob',
    lastName: 'jones',
    age: 33,
  },
  {
    firstName: 'jane',
    lastName: 'snith',
    age: 20
  },
];

as the value of persons .

We created the getFirstIndex method that takes an arr array and the person object.

Inside the function, we call findIndex to return the first index with of the array entry with the given value of person.firstName , person.lastName , and person.age .

Then in the filter callback, we can call getFirstIndex to compare the index with the returned index.

If they’re different, then we know the object is a duplicate, so it’ll be discarded.

In the end, we get the same result.

Create a Map and Convert it Back to an Array

Another way to remove the entries is to create a map from the array and then convert it back to an array.

For instance, we can write:

const map = new Map();for (const p of persons) {
  map.set(JSON.stringify(p), p);
}

const uniquePersons = [...map.values()]

given that person is the same as the other examples.

We just add the items into the map with the set method. The stringified version of the object if the key and the non-stringified version is the value.

Since strings can be compared with === , duplicates will be overwritten.

Then we can spread the items back to an array by getting them with map.values() and using the spread operator.

Conclusion

Removing duplicate objects takes more work than removing duplicate primitive values.

Array methods and maps make this easier.

Categories
JavaScript Basics

Highlights of JavaScript — Form Validation and Event Handling

To learn JavaScript, we must learn the basics.

In this article, we’ll look at the most basic parts of the JavaScript language.

Dropdown Validation

We can add validation to select dropdown fields.

For example, we can write the following HTML:

<form onSubmit="return checkForSelection();">
  <select id="fruits">
    <option value="" selected="selected">
      SELECT A FRUIT</option>
    <option value="apple">apple</option>
    <option value="orange">orange</option>
    <option value="grape">grape</option>
  </select>
  <br>
  <input type="submit" value="Submit Form">
</form>

And then add the following JavaScript:

const checkForSelection = () => {
  if (document.getElementById("fruits").selectedIndex === 0) {
    alert("Please select a fruit.");
    return false;
  }
}

We added a select element and when we click on Submit Form, the checkForSelection function is run.

We add the return keyword so that we stop the default submit behavior and let the checkForSelection run.

Radio Button Validation

Also, we can add validation to a group of radio buttons.

For instance, we can write the following HTML:

<form onSubmit="return validateRadios();">
  <input type="radio" name="r1" value="apple"> apple<br>
  <input type="radio" name="r1" value="orange"> orange<br>
  <input type="radio" name="r1" value="grape"> grape<br>
  <input type="submit" value="Submit Form">
</form>

And the following JavaScript:

const validateRadios = () => {
  const radios = document.getElementsByName("r1");
  for (const r of radios) {
    if (r.checked) {
      return true;
    }
  }
  alert("Please check one.");
  return false;
}

We have a form with a bunch of radio buttons with the same name attribute value.

They should have the same name so that they’re considered to be in the same group.

When we click the Submit Form button, the validateRadios function runs.

In the function, we get all the radio buttons by calling getElementsByName with the name attribute value of the radio buttons.

We loop through the radio buttons with the for-of loop.

Then if one is checked, we return true .

Otherwise, we show an alert and return false is none of them are checked.

Email Validation

We can validate email address in a form field by checking the format of the entered text with a regex.

For example, we can write the following HTML:

<form onSubmit="return validateEmail();">
  Please enter your email.<br>
  <input type="text" id="emailField">
  <input type="submit" value="Submit">
</form>

And write the following JavaScript code:

const validateEmail = () => {
  const emailField = document.getElementById("emailField");
  const regex = /^[\w\-\.\+]+\@[a-zA-Z0-9\. \-]+\.[a-zA-z0-9]
  if (!(regex.test(emailField.value))) {
    alert("Please correct email address");
    return false;
  }
}

We have the validateEmail function that gets the value of the input with ID emailField .

Then we call the regex.test method to check if the inputted value matches the regex format.

If it doesn’t then we show an alert and return false .

The return keyword lets us prevent the default submit behavior from running.

Handling Events

We can attach event listeners to HTML elements.

For example, we can write the following HTML:

<input type="button" value="Click" id='button1'>

And write the following JavaScript:

const b1 = document.getElementById("button1");
const sayHello = () => {
  alert('hello');
}
b1.onclick = sayHello;

We get the button with getElementById .

Then we set the onclick property to the sayHello event handler function.

The functions show an alert with the alert function.

Now when we click on the button, we show the alert.

Conclusion

We can add form validation and the add event handlers to HTML elements so that we can do what we want when the user does something to the element.

Categories
JavaScript Basics

Highlights of JavaScript — Popup Windows and Input Validation

To learn JavaScript, we must learn the basics.

In this article, we’ll look at the most basic parts of the JavaScript language.

Opening Popup Windows

We can open popup windows with the window.open method.

For example, we can write:

const monkeyWindow = window.open();

To add some content to the window, we can write:

const monkeyWindow = window.open();
const windowContent = `<h1>hello world</h1>`;
monkeyWindow.document.write(windowContent);

We call document.write on the monkeyWindow to show the content.

Also, we can show the content of a URL with the location.assign method:

const monkeyWindow = window.open();
monkeyWindow.location.assign("https://www.google.com");

Now we should see Google displayed in the new window.

We can also write:

const monkeyWindow = window.open();
monkeyWindow.location.href = "https://www.google.com";

to do the same thing.

To close a window, we can write:

const monkeyWindow = window.open();
monkeyWindow.location.href = "https://www.google.com";
monkeyWindow.close();

Controlling the Window’s Size and Location

We can set the popup window’s size and location with a string in the 3rd argument of window.open .

For example, we can write:

const monkeyWindow = window.open("https://www.google.com", "win1", "width=420,height=380");

Now the window is 420px in width and 380px for height.

To change its location, we can write:

const monkeyWindow = window.open("https://www.google.com", "win1", "width=420,height=380,left=200,top=100");

to add the left and top keys to set the position.

Form Validation

We can add form validation to a form.

For example, we can write the following HTML:

<form onSubmit="return checkForLastName();">
  Please enter your last name.<br>
  <input type="text" id="lastNameField">
  <input type="submit" value="Submit">
</form>

And we can add the following JavaScript to add the validation:

const checkForLastName = () => {
  if (document.getElementById("lastNameField").value.length === 0) {
    alert("Please enter your last name");
    return false;
  }
}

In the checkForLastName function, we get the value of the input with the ID lastNameField .

If the value ‘s length is 0, then we show the alert.

The return in the onSubmit attribute value makes sure that we prevent the default submit behavior along with the return false in checkForLastName so that we can run the JavaScript validation.

To improve the user experience, we can call focus on the element:

const checkForLastName = () => {
  const lastNameField = document.getElementById("lastNameField")
  if (lastNameField.value.length === 0) {
    alert("Please enter your last name");
    lastNameField.focus();
    return false;
  }
}

We call focus on the input element so that the user can type in the text without clicking on the input.

Also, we can add background color so that the user can see the input field more easily:

const checkForLastName = () => {
  const lastNameField = document.getElementById("lastNameField")
  if (lastNameField.value.length === 0) {
    alert("Please enter your last name");
    lastNameField.focus();
    lastNameField.style.background = "yellow";
    return false;
  }
  lastNameField.style.background = "white";
}

We set the background color by setting the lastNameField.style.background property.

Conclusion

We can open windows with our own content.

Also, we should add form validation for fields so that users always input valid data.

Categories
JavaScript Basics

Highlights of JavaScript — Constructor Methods and Getting URLs

To learn JavaScript, we must learn the basics.

In this article, we’ll look at the most basic parts of the JavaScript language.

Constructor Methods

We can add methods to constructors or classes.

For example, we can write:

class Plan {
  constructor(name, price, space, pages) {
    this.name = name;
    this.price = price;
    this.space = space;
    this.pages = pages;
  }

  calcAnnualPrice() {
    return this.price * 12;
  }
}

We add the calcAnnualPrice method to return the value of this.price * 12 .

this is the class instance, which is the object that’s created and returned when we invoke the Plan class.

So we get the price property from the object we create from the class and multiply it by 12.

To invoke the constructor and call the method on the created object, we can write:

const plan = new Plan('basic', 3, 100, 10)
console.log(plan.calcAnnualPrice())

We invoke the Plan constructor with the new keyword.

Then we call calcAnnualPrice on the plan object to get the annual price.

The class syntax is just syntactic sugar on top of prototype inheritance.

The calcAnnualPrice method is just a property of the Plan ‘s prototype property.

The prototype is the prototype of the Plan class, which is the object that it inherits from.

If we log the value of Plan.prototype.calcAnnualPrice :

console.log(Plan.prototype.calcAnnualPrice)

we see the code of the calcAnnualPrice method logged.

Checking for Properties and Methods

To check if a property or method is actually in the object itself rather than its prototype, we can use the hasOwnProperty method.

For example, if we created an object from the Plan class:

const plan = new Plan('basic', 3, 100, 10)

Then we can call hasOwnProperty by writing:

console.log(plan.hasOwnProperty('name'))

Then we should see true logged since name is a property of the plan object itself.

The hasOwnProperty method comes from Object.prototype , which is a property of almost all JavaScript objects.

If we want to list an object’s properties, we can write:

for (const prop in plan) {
  if (plan.hasOwnProperty(prop)) {
    console.log(prop);
  }
}

We loop through the plan ‘s property keys with the for-in loop.

The for-in loop loops through all then properties and its prototypes, so we have to use the hasOwnProperty method to check if a property is actually in the plan object itself.

prop is the property name itself.

Therefore, we should see:

name
price
space
pages

logged.

Getting the URL

We can get and set the URL of the page with JavaScript.

To get the URL, we can use the window.location.href property.

If we type that into the browser dev console, we should get the full URL of the page.

window.location.hostname has the hostname which is the first part of the URL.

For example, if we have the URL“https://jsfiddle.net/09t6La27/10/" , then window.location.hostname returns “jsfiddle.net” .

window.location.hash returns the part of the URL after the # sign.

For example, if we have http://example.com/#foo , window.location.hash returns “#foo” .

Conclusion

We can add methods to constructors or classes.

Also, we can get parts of a URL with the window.location object.