
Understanding some of the key concepts in JavaScript
JavaScript, like any other programming language, has its tricky bits which can sometimes be a little overwhelming. In this article, I would like to throw some light at how to correctly implement some of them. I will use a concrete example which collects some of these concepts. Enjoy!
As you may already know, JavaScript allows for various programming styles. Most programmers use the imperative (procedural) style — a set of functions which are executed step by step. But you can also write JavaScript in functional or object-oriented style. Although the most common way for writing JavaScript for the client is imperative, I decided to structure the code in a readable and compact object-oriented style. A good fit for writing OO JavaScript is TypeScript but for the sake of the example below I will be using the good old prototypes.
Let’s assume our file is called concept.js. Then the main class is named Concept. You can define a ‘class’ in several ways. Using JavaScript classes, introduced in ES6 (the JS version from 2015), or just with a normal function declaration. We will be using the latter. A distinction between a ‘class’ and a normal ‘function’ can be done by naming the ‘class’ with a capital letter.
The function acts as a constructor of the class and objects can be declared as shown on line 4. In this case the special keyword this is equal to the Concept object and makes the variable concept accessible from any method inside the class. If we don’t attach concept to the current object, then we won’t be able to access it anywhere else except inside the scope of the function Concept. The keyword this can be confusing sometimes so if you want to understand how to use it correctly it is worth reading the documentation.
In order to create methods for our class Concept we need to do the following:
Here we used the special keyword prototype which adds the method directly to the object’s prototype. This is the same as writing:
Now let’s implement the 3 functions and dive into some of the sophisticated concepts of JavaScript.
Let’s first define our task. Say we have a really big list (1000+ elements) with emails of our users. In our database we have stored each email together with an associated image url pointing to their profile picture. We want to fetch those images and say if they contain a face. Finally we want to display the result: yes or no.
But what is so tricky about this objective? There are two things we need to keep in mind: fetching the database and checking for a face are two requests which depend on each other and we don’t want to wait for receiving all results before displaying them (this may take forever if we have even larger list).
I will gradually implement the solution so it is easier for you to follow. Let’s first rename our functions and add the appropriate parameters.
Both fetchImageURL
and checkFaceExistence
need to request our server, wait for response and notify displayImages
for the outcome. But some of these requests may take longer or even fail and we want to know what has happened. In order to successfully accomplish this we need to use Promises.
The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value. — MDN web docs
As stated in the definition the Promise will hold the result (or failure) of our request and will provide it to us when it is ready. This means that we don’t need to just sit and wait but can do something else while the asynchronous operation is being executed. I will leave the detailed explanation of Promises to Nolan Lawson and his amazing article.
As now we are familiar with Promises, I will reveal the implementation of fetchImageURL
:
The function is just a simulation of an Ajax request which returns imageURL if successful and error if not. You may wonder what are resolve and reject. These functions are just callbacks which determine if the Promise is successful or not. We will see how they reflect the output of fetchImageURL
later.
Now we will implement checkFaceExistence
which will follow the same structure as fetchImageURL
:
If you want to use a good API for face recognition, I strongly suggest the Microsoft’s one. It is part of a broader set of Artificial Intelligence APIs collected in the Microsoft Cognitive Services. They are amazing for a hackathon, personal project or even if you own a start-up and want to benefit from the emerging power of AI.
Since we are done implementing the two helper function, now let’s focus on the one which combines everything together in displayResults
.
First, we will introduce Promise.map. It takes an Iterable (list, array) of elements or Promises, iterate over it and map it to another list (array). This is wonderful since we don’t need to wait for every Promise to resolve before running the next one. We execute them one by one and the order of return is based on the speed of each request. So we are able to show the result from the face detection process for a single photo immediately after receiving it.
But there is one thing you need to keep in mind. If you are limited to a small CPU space and your requests take longer time, you may exceed your memory. In this case, you need to add a special parameter {concurrency: n}
just after the callback function inside Promise.map. This will limit the number of Promises ran simultaneously to n.
Now we need to perform both requests sequentially for every email and return the result from the face detection. We will do this as follows:
Let’s break down the above piece of code.
Line 3 returns a Promise as we can see from the implementation of fetchImageURL
— exactly what Promise.map requires. Using the keyword .then
we receive the successfully resolved value from the Promise and plug it into our next Promise — checkFaceExistence
. Line 4 is interesting because by usingcheckFaceExistence
we are actually returning a Promise object which will be resolved successfully in the next .then
. This is the same as writing this.checkFaceExistence(imageURL).then(exists => {...})
. The difference comes in readability and the fact that here only one .catch
statement would do the job properly (I am explaining the .catch
below). Both ways are accepted but, for me, the above example is an amazing pattern for sequentially chaining multiple Promises which depend on each other.
Finally we print (display) the result together with the correct email and user index. Using the keyword .catch
we can detect a rejection of any of the above Promises so if fetchImageURL
or checkFaceExistence
fails we will be able to react accordingly. If we were to attach .then
to this.checkFaceExistence
, we would also need a different .catch
— this.checkFaceExistence(imageURL).then(exists => {...}).catch(error => {...})
.
There is only one tiny detail which we have missed. Unfortunately, if you try to run the above function it wouldn’t work because it would throw an error stating that fetchImageURL
is not declared. But why is that? Since we chose an object-oriented style of programming, the Promise.map callback is not attached to the Concept object. This means that we explicitly need to specify what the this
object inside the callback needs to refer to. So here is how the final version of displayResults
should look like:
You can notice that I have added .bind(this)
just after the callback. Basically, this is saying: “wherever you see this
inside the callback function, interpret it as the object specified inside .bind()
” . In our case the object inside .bind()
is the Concept object referenced with this
.
Putting everything together gives us a working solution to the task we set earlier.
I hope this article is leaving you more confident in your knowledge about some of the key concepts in JavaScript and gave you a good list of resources to enhance your skills.