Categories
JavaScript Best Practices

JavaScript Best Practices — Performance Improvements

Like any kind of apps, JavaScript apps also have to be written well.

Otherwise, we run into all kinds of issues later on.

In this article, we’ll look at some best practices we should follow when writing JavaScript code.

Excess Optimizations

We shouldn’t optimize our code too much.

If there aren’t obvious performance issues then we can leave it.

And if it makes our code harder to work it, we shouldn’t make the change.

Causing Excessive Document Reflows

DOM modification is slow since our browser has to rebuild the DOM tree and recalculate all the dimensions to see how they fit together.

It’s more of a problem if elements have the default static positioning or relative.

So we should keep DOM modifications to a minimum.

To reduce the operations, we should batch our DOM manipulation.

For example, we can write:

let div = $('<div></div>');

$('body').append(div);

for (let i = 0; i < 10000; i++) {
  $('div').append(
    '<p>foo</p>'
  );
}

We append to p elements to the div 1000 times.

This is obviously going to be very slow.

Instead, we should only call append on the body one time:

let div = $('<div></div>');

for (let i = 0; i < 10000; i++) {
  $('div').append(
    '<p>foo</p>'
  );
}

$('body').append(div);

In the code above, we call append to append the p elements to the div, which isn’t in the DOM yet.

So we won’t be changing the DOM 10000 times.

The only change is the last line where we append the div to the body.

Going Overboard with File Concatenation

We shouldn’t concatenate everything into one big file.

One big request may be slower than multiple smaller requests.

This is because once a request is made for the resource, it’ll be cached until it’s updated again.

Having multiple smaller files can take advantage of that.

If we have one big file, then we can’t take advantage of the caching.

The best way to combine the code is to have one common file that’s used everywhere.

And then we have page-specific files that are only used on the page requested.

Really Long Function Chains

Function chains can be handy.

But we should be aware that we may have null or undefined returned in the middle of the chain.

For example, if we have:

$('.el').click(handleClick).parents('.container')[0].slideDown();

then any of the methods could return those values and crashing our app.

Flash of Unstyled Content (FOUC) Because of Late-Loading JavaScript

We may see unsettled content for a brief period before showing the right design.

The best way to improve the situation is to reduce the amount of DOM manipulation on the initial load.

Also, we should specify the height and width of the pages in our HTML instead of JavaScript so that we don’t have to wait for JavaScript to load to set them.

Another way to deal with it is to mask the problem with CSS or JavaScript animations.

We can also block rendering until all content on the page has been loaded.

The offending JavaScript can be inlined and put beneath the affected DOM element.

This way, the code loads immediately when the element is loaded.

However, this is hard to maintain and should be used sparingly.

We can write:

<div class="fouc-element">
  <script>
    // ...
  </script>
  ...
</div>

to do that.

Conclusion

We can improve performance with various optimizations.

Categories
JavaScript Best Practices

JavaScript Best Practices — Compression and Animation

Like any kind of apps, JavaScript apps also have to be written well.

Otherwise, we run into all kinds of issues later on.

In this article, we’ll look at some best practices we should follow when writing JavaScript code.

Compress Built Files

We should compress built files with gzip, Brotli, or other compression methods so that users don’t have to download as much data.

The less code users have to download, the faster the loading time will be.

Limit Library Dependencies

We should limit the libraries that we use.

There’re smaller alternatives and we can remove the ones that are built into the JavaScript standard library.

Minify our Code

Before putting our code on production, we should minify them so that the size of the files are smaller.

There’re many tools to let us do this.

Frameworks have tools that use Webpack to minify files without doing any work.

There’re also other libraries like Parcel to do the same thing.

Add Post-Load Dependency Managers

Webpack also lets us manage our dependencies.

This include non-JavaScript files like CSS files and images.

They can be loaded as modules with Webpack for example.

They can also track JavaScript dependencies.

This way, nothing is loaded twice and avoid other issues.

Cache as Much as we Can

Caching reduce the number of requests that have to be made to get assets.

They’ll only be downloaded again when the cache expires.

This will speed up loading times.

We can also use content delivery networks to speed up delivery to users.

Mind our Event Handlers

Some event handlers like mousemove or resize run every time those actions are taken.

This means they’ll run many times in quick succession.

An event handler shouldn’t take more than 2 to 3 ms to run.

If it takes longer, then we need to optimize our code.

Replace click with mouseup

Mouseup fires before the click event provide a performance boost by ensuring no interactions are missed if users make multiple mouse clicks in quick succession.

Use Reference Types Responsibly

If we use reference types, then they can be passed around into different parts of the code.

They’re passed by reference into functions.

This can let us cut down on the number of DOM traversals needed.

Primitive values are always passed by value into functions so a copy is made everywhere.

Comparing references if always faster than comparing strings.

Favor Native Functions and Constructs

If something is available in the JavaScript standard library or available as a language feature, then we should use it.

This lets us reduce the number of dependencies that we use.

Prefer async and defer

We should use the async and defer attributes to load scripts asynchronously.

async load scripts asynchronously without regard to order.

defer load scripts asynchronously one after the one as listed in the code.

They can let us load other things while waiting for the scripts to load.

Animate with requestAnimationFrame

requestAnimationFrame fixes the rendering at 60 FPS.

Therefore, if our animation is running slow, we can use requestAnimationFrame to get them up to speed.

Conclusion

We can minify our code to speed them up.

Also, there’re ways to improve animation speed.

Categories
JavaScript Best Practices

JavaScript Best Practices — Bundling

Like any kind of apps, JavaScript apps also have to be written well.

Otherwise, we run into all kinds of issues later on.

In this article, we’ll look at some best practices we should follow when writing JavaScript code.

Don’t Bundle Everything Together

We shouldn’t bundle everything together into one big package.

HTTP/2 no longer has bi overhead when making multiple HTTP requests.

Therefore, there’s no advantage to bundling everything up.

Browser caching is also hard with this approach since any change will invalidate the cache.

This will force users to download everything again.

That results in lots of wasted bandwidth.

HTTP/2 is supported by 95% of the clients worldwide, so we can assume that we don’t need to bundle everything together.

Best Way to Bundle Items

Separate vendor and client code is the best approach

This solves the issue where a small change will force the user to download everything again.

If our own code changes, then only the client code is changed.

The vendor code remains the same since we didn’t change the library code.

This saves us lots of bandwidth.

With Webpack, this requires extra code-splitting config to tell Webpack where the vendor code lives.

They should live in the node_modules folder.

So in the built index.html file, we get:

<script src="vendor.[hash].min.js"></script>
<script src="index.[hash].min.js"></script>

We can improve this further.

The vendor file can be split into smaller pieces.

For example, we can write:

<script src="vendor.react.[hash].min.js"></script>
<script src="vendor.others.[hash].min.js"></script>
<script src="index.[hash].min.js"></script>

to split the React files from the rest of the library files.

This is because the React libraries change slower than the other ones, so we can keep them cached separately.

Public CDN

We shouldn’t keep all our dependencies in the bundles instead of having some in the CDN.

The code is downloaded once per domain and the cache is sandboxed because of privacy implications.

This is because of the partitioned cache feature that separates the caches for users from different domains.

Also, using CDN means that we need to do all the request stuff for every domain.

DNS resolution, initial connection, and SSL handshake all required to be done.

Hitting the CDN means that we have to do those things for one more domain.

So having everything in the same domain will reduce the overhead.

Vendor versions would also be fragmented since the library versions on different CDNs are different.

If we browse from one site that uses one CDN and another that uses a different one, then they’ve to be downloaded again.

CDNs can also have other issues like malicious code injected into them.

Privacy may also be a concern since some people may harvest data from 3rd party requests.

And CDNs are a single point of failure.

The Best Way

Therefore, the best way is to use packages for all our dependencies and then build them into vendor and index JavaScript files.

Then we can put them behind our own non-shared CDN so that they can be downloaded by users and cached until we deploy the next set of changes.

They can be smaller because of HTTP/2 caching and fast performance when making multiple requests.

Conclusion

We should bundle our files into chunks consisting of one or more with 3rd libraries and another with our own code.

Categories
JavaScript Best Practices

Reducing Headaches with Some JavaScript Best Practices

Like any kind of apps, JavaScript apps also have to be written well.

Otherwise, we run into all kinds of issues later on.

In this article, we’ll look at some best practices we should follow when writing JavaScript code.

Declare All Variables First

To make finding variables easier, we can declare them at the top.

For example, instead of writing:

function foo(){
  let i = 100;
  console.log(i);
  let j;
}

We write:”

function foo(){
  let i = 100;
  let j;
  console.log(i);
}

This way, we won’t have a hard time looking for variable definitions.

We also don’t have to worry about hoisting when using var or function declarations.

Be Careful Using typeof

We’ve to know that typeof null returns 'object' .

So we can’t use it to check for null .

Also, typeof NaN returns 'number' , which is probably not what we expect.

So we shouldn’t use them to check for those.

Treat parseInt With Care

parseInt also have some quirks we’ve to think about.

It returns all of the number characters it finds converted to the number.

So if we have:

parseInt("11");

It’ll return 11.

And if we have:

parseInt("11james");

This will also return 11.

And if we have:

parseInt("11.22");

This also returns 11.

We should take note of these quirks so that we won’t get unexpected results when we try to convert non-numbers to numbers with parseInt .

Also, if the number starts at 0, it’ll assume that it’s an octal number.

So if we have:

parseInt("08");

then it’ll return 0 in older browsers.

However, in modern browsers, it should be converted as a decimal number.

Do Not Use Switch Fall Through

In each case clause of switch statements, we should have a break or return statement at the end of the clause.

For example, we write:

switch (val) {
  case 1:
    console.log('One');
    break;
  case 2:
    console.log('Two');
    break;
  case 3:
    console.log('Three');
    break;
  default:
    console.log('Unknown');
    break;
}

so that the JavaScript interpreter won’t run code below the case clause that’s matched.

Avoid For…In Loops

for-in loops should be avoided for arrays.

It doesn’t guarantee iteration order and it’s slower than the standard for loop.

It’s intended for iterating through an object’s noninherited and inherited properties.

This means the following loops aren’t equivalent:

for (let i = 0; i < arr.length; i++) {}

for (let i in arr) {}

If we want to iterate through an array in a shorter way, we can use the for-of loop:

for (let a in arr) {}

a is the array entry.

Avoid Reserved or Special Words

We shouldn’t use reserved words to define our own identifiers.

This may be allowed if strict mode is off.

For example, we may define functions like:

function foo(arguments){}

which is allowed if strict mode is off.

If it’s on, then we’ll get an error.

This is one good reason to turn on strict mode.

We can avoid defining our own identifiers that have the same name as a reserved word.

Be Consistent

We should be consistent with our code styling.

This can be done easily with ESLint.

It’s good at fixing these styling issues for us so we won’t have to worry about them.

Conclusion

We can reduce headaches by following some easy to follow rules.

Categories
JavaScript Best Practices

JavaScript Best Practices — Assumptions and Optimizations

Like any kind of apps, JavaScript apps also have to be written well.

Otherwise, we run into all kinds of issues later on.

In this article, we’ll look at some best practices we should follow when writing JavaScript code.

Use the Module Pattern to Encapsulate

We can use the module pattern to encapsulate our code.

This lets us keep private variables in any JavaScript code.

For example, we can write:

(function(){
  let x = 123;
  console.log(x);
})();

We have the variable x that’s only available inside the function.

It’s also useful when classes or constructors don’t make sense.

Namespace Our JavaScript

If we need to refer our JavaScript code else, we should namespace them to make them easy to find.

For example, we can write:

let MyNamespace = MyNamespace || {};

MyNamespace.MyModule = () => {
    // ...
}

our namespace has properties, which include objects we use as a module.

Anonymously Scope JavaScript

We should scope our JavaScript if we aren’t calling it anywhere.

For example, we can write:

(function(){
  let x = 123;
  console.log(x);
})();

to scope the JavaScript to be inside the function only.

This makes our variables available only inside the function.

And we can’t modify them accidentally.

Focus on the Big Things when Optimizing

The big performance improvements can come from a few places.

DOM operations are expensive so we should do them as little as possible.

Anything that forces a page to re-rerender isn’t optimal.

Events that are fired all the time like resizing and scrolling can also be denounced or throttled.

If we have lots of HTTP requests, we can also reduce them.

These are problems we can address to increase responsiveness.

Lazy Load Assets that aren’t Immediately Required

If we have assets that aren’t shown to the user immediately, then we should lazy load them.

This way, they’re only loaded when they’re needed to be shown.

unbind() All Event Handlers Before Binding

We should unbind all event handlers so that we don’ t have multiple event handlers bound to elements.

For example, we can write:

$("a.some-link").unbind(handleClick).click(handleClick);

to unbind the existing event listeners and then attach a new click listener to the a link.

This ensures that it’s only bound once.

Since we need this everywhere, we can create a helper function to help us do this everywhere.

Don’t Treat JavaScript Like a Classical OOP Language

We shouldn’t treat JavaScript like a classical OOP language.

Even though the class syntax exists, it’s just syntactic sugar on top of its prototypical inheritance model.

This has never changed.

So even though JavaScript has classes, it’s not a classical OOP language.

Don’t Abuse Inlining of Functions and Object Literals

Deep nesting is definitely bad.

They make code hard to read.

The deeper the nesting, the harder it is to follow.

For example, no one wants to read something like:

var myFunction = function() {
  $('form#my-form').submit(
    function(event) {
      event.preventDefault();
      $.ajax(
        '/some_service', {
          type: "POST",
          data: {
            name: name,
            name: company
          },
          success: function(data) {
            onSuccess({
              response1: data.value1,
              response2: data.value2
            })
          },
          error: function(data) {
            onError({
              response1: data.value1,
              response2: data.value2
            })
          }
        }
      );
    }
  );
};

We should make this easy to read by reducing nesting.

Inlining everything also makes functions and variables impossible to reuse.

Conclusion

We can create modules to separate values.

Also, we unbind event handlers with jQuery before attaching them.

And don’t abuse inlining and treat JavaScript as a classical OOP language.