CEOToolSuite EcmaScript Style & Conventions
10 years ago I started out on a quest to distill a full comprehension of javascript down to a functional set of conventions. Much of the internet is bogged down with javascript libraries atop other javascript libraries. Many times pages load slowly because of an incorrect management of web technologies. It's easy to overcomplicate frontend and adding frameworks certainly doesn't help. Most frameworks are reinventing the wheel. The ECMAScript standard has everything needed for fast performant sites. If a library is to be used it should be for a specific niche purpose & only if writing a custom solution would take much more time or the library is simply foundational (think bluebird promises before the Promise object was standardized).
To this end below is a set of conventions I've found to be helpful in writing vanilla js sites.
_
The underscore is helpful for simplifying patterns. There's no point in naming a throw away variable.
Namespacing
By using namespacing, variables (effectively) never collide.
window.namespace__subspace = {
e: {},
f: {},
g: {},
};
- e - Element cache for DOM references
- f - Functions for utilities and methods
- g - Globals for constants, state, and configuration
Variable Declarations
Always use var, never use const or let. This is intentional - var has function scope which is more predictable and hoisting behavior is well understood. const and let add complexity with block scoping that rarely provides real benefits in well-structured code.
Async Operations
Always use async/await over promises with .then() chains. The code is more readable and easier to debug:
// note: preferred
var data = await (await fetch(url)).json();
// note: avoid
fetch(url).then(r => r.json()).then(data => {});
Error Handling
Avoid try/catch blocks - let errors surface for debugging. In production, errors should be caught at the top level and logged appropriately. Wrapping every operation in try/catch hides bugs and makes debugging harder.
Naming Conventions
- double underscore (
__) separates namespace parts:namespace__subspace - single underscore (
_) separates words within names:word_in_phrase - never use hyphens in identifiers
DOM Access
Cache DOM elements in the e object rather than querying repeatedly. Use a refresh_elements() function that automatically populates the cache:
Note the qsa, this is a special case and recommendation for the ECMAScript standard:
window.qsa = document.querySelectorAll.bind(document);
More examples can be found in the example utility file @ the end.
namespace__subspace.f.refresh_elements = () => {
namespace__subspace.e = {};
for (var _ of qsa('[namespace__subspace]')) {
var tagname = _.tagName.toLowerCase();
var handle = _.getAttribute('namespace__subspace').toLowerCase();
namespace__subspace.e[`${tagname}__${handle}`] = _;
}
};
^^ refresh_elements is a phrase thus single underscore.
<button namespace__subspace="submit">Submit</button>
namespace__subspace.e.button__submit.addEventListener('click', namespace__subspace.f.namespace__subspace);
Timing & Race Conditions
With a few basic functions code becomes self documenting & timing issues disappear.
namespace__subspace.f.load__style
namespace__subspace.f.load__script
namespace__subspace.f.load__html
namespace__subspace.f.wait_for_self
namespace__subspace.f.wait_for_load
namespace__subspace.f.wait_for_elem
see example file @ the end.
No Frameworks
Vanilla javascript is sufficient, frameworks add technical debt.
- bundle size overhead
- learning curve
- version upgrade maintenance
- abstraction that hides what's actually happening