To make code easy to read and maintain, we should follow some best practices.
In this article, we’ll look at some best practices we should follow to make everyone’s lives easier.
No Assignments that Lead to Race Conditions with await or yield
await
is always async and yield
can also be async, so if we make assignments in parallel, then it’ll lead to race conditions.
For instance, if we have:
let length = 0;
async function addLength(pageNum) {
length += await getPageLength(pageNum);
}
Promise.all([addLength(1), addLength(2)]).then(() => {
console.log(totalLength);
});
Then we don’t know when addLength
for each call will finish.
We should run these in sequence like:
async function addLengths() {
const length1 = await addLength(1);
const length2 = await addLength(2);
return length1 + length2;
}
No async Functions Which have no await
Expression
We shouldn’t have async
functions that have no await
expressions.
If there’s no await
, this means we aren’t using promises it, so we don’t need the async
keyword.
For instance, instead of writing:
async function foo() {
doWork();
}
We write:
async function foo() {
await doWork();
}
JSDoc Comments
We can use JSDoc comments to explain the parameters and describe what the function does.
For instance, we can write:
/**
* Multiplies two numbers together.
* @param {int} num1 The first number.
* @param {int} num2 The second number.
* @returns {int} The product of the two numbers.
*/
function multiply(num1, num2) {
return num1 * num2;
}
param
explain the parameters and returns
explains what the returned result is.
The top has the function description.
Use the u
flag on RegExp
We should use the u
flag in our regex so that UTF-16 character pairs are handled correctly.
For instance, instead of writing:
/^[?]$/.test("?")
We write:
/^[?]$/u.test("?")
The first one returns false
, which is wrong.
But the second returns true
, which is right. This is because we added the u
flag.
No Generator Functions that do not have Yield
A generator function without yield
doesn’t need to be a generator.
So instead of writing:
function* foo() {
return 10;
}
We write:
function* foo() {
yield 20;
return 10;
}
Spacing Between Rest and Spread Operators and their Expressions
We don’t need spaces between the rest and spread operations and their expressions.
For instance, instead of writing:
let arr2 = [1, 2, 3];
arr1.push(... arr2);
or:
fn(... args)
We write:
let arr2 = [1, 2, 3];
arr1.push(...arr2);
or:
fn(...args)
Automatic Semicolon Insertion (ASI)
We should put the semicolons ourselves so that we know where each line starts or ends.
For instance, we can write:
let n = 0
const increment = () => {
return ++n
}
We write:
let n = 0;
const increment = () => {
return ++n;
}
Spacing Before and After Semicolons
We should have one space after the semicolon if there’s something after it
For instance, instead of writing:
var c = "foo";var e = "bar";
We write:
var c = "d"; var e = "f";
Location of Semicolons
We should put semicolons where it makes sense.
For instance, instead of writing:
foo()
;[1, 2, 3].forEach(bar)
We write:
foo();
[1, 2, 3].forEach(bar);
It’s more conventional and clearer.
Import Sorting
We can sort our imports to make them easier to follow.
For instance, instead of writing:
import b from 'foo.js';
import a from 'bar.js';
We write:
import a from 'bar.js';
import b from 'foo.js';
Sort Object Keys
We can sort object keys alphabetically to make them easier to find.
So instead of writing:
let obj = {
a: 1,
c: 3,
b: 2
};
We write:
let obj = {
a: 1,
b: 2,
c: 3,
};
Sorting Variables
We can sort variables to make them easier to find,
For instance, instead of writing:
var b, a;
We write:
var a, b;
Conclusion
We can sort object properties, variables, imports, etc,. to make them easier to find.
Also, we put the semicolons in conventional places to make them easier to read.
The u
flag should be in a regex to make JavaScript search for character pairs properly.
If there’s no await
, then we don’t need an async
function.
If there’s no yield
, then we don’t need a generator function.