Responsible JavaScript Development Part 1
- Transfer
The numbers tell us that the growth of JavaScript code has a bad effect on the performance of web projects. If this continues further, then very soon, when loading the middle page, at least 400 Kb of JS code will be transferred. And this is just the amount of data transferred. Like other text resources, JavaScript code is almost always transmitted in a compressed form. Compression is probably the only thing that is usually done correctly when transferring code from the server to the client.
Unfortunately, while reducing the transfer time of certain resources makes a serious contribution to what we call “performance”, compression does not affect how much time the browser takes to parse and process the script after it is fully loaded .
If the server sends 400 KB of compressed JS code to the client, then the actual amount of code that the browser needs to process after decompressing the received data will be in the megabyte area. How well different devices handle this kind of work depends on the devices themselves. Much has been written about this , but we can only say with certainty that the time required even to parse the amount of code that is quite usual for its time varies greatly between different devices.
Take a look, for example, at thismy simple project. During page loading, about 23 Kb of uncompressed JS code is transferred to the client. Chrome, running on the MacBook Pro, which was released in mid-2017, processes this rather small amount of code in about 25 ms. On the Nokia 2 Android smartphone , however, a similar figure expands to 190 ms. This is not to say that it is very small, but in any case, the page becomes interactive quickly enough.
Now, an important question. What do you think, how does a simple Nokia 2 smartphone manage average modern pages? In fact - just awful. Browsing web pages, even on a fast Internet connection, forces the user to exercise patience, since working with pages loaded with JavaScript code becomes possible only after a hefty waiting period.
Performance overview of Nokia 2 when viewing a page containing a large amount of JS code, processing of which blocks the main stream.
Although the devices with which they use to view web pages and the networks through which data is transmitted have significantly improved in recent years, studies show that all these improvements are "eaten up" by large amounts of JS-code included in the pages. We need to use JavaScript responsibly. Responsibility begins with an understanding of what we are creating and how we do it.
Strange things happen with inaccurate terms that we use to name something, although their meanings, on an intuitive level, are clear to everyone. Sometimes we overload the meaning of the word “bee”, calling it “bees” and wasps, even though the difference between bees and wasps is very significant. Taking into account such differences can lead to the fact that the “bees” and “wasps” will act differently. For example, we are going to destroy a hornet’s nest, but if we are talking about bees, insects are much more useful and vulnerable, their nest, located in the wrong place, will probably be decided not to destroy, but to transfer it somewhere.
Similar freedom can be observed in the way we use the terms “website” and “web application”. The differences between these concepts are much less obvious than the differences between real wasps and honey bees, but if these concepts are combined, this can lead to very unpleasant consequences. Troubles begin when we allow ourselves something, depending on whether a project is “just a website” or “a full-blown web application”. If you are creating an information site for a company, then most likely you will not rely on a powerful framework for managing DOM changes or for implementing routing on the client. At a minimum, I hope so. Using tools that are poorly suited to solve certain problems will not only harm those who will use the site, but also, probably
When developing a web application, everything looks different. We install packages, which is accompanied by the addition of hundreds, if not thousands, of dependencies to the project. Moreover, we are not even sure of the safety of some of them. We write complex configurations for bundlers. When working in such a ubiquitous crazy development environment, you need knowledge and attention in order to make sure that what was collected is quick, that the project will work where it should work. If in doubt, run the npm ls --prod command in the root directory of your project and see if you can name the purpose of using all of that.that this command will output. Even if you can do it, this does not apply to third-party scripts. I am sure several such scripts are also used in your project.
We forget that both websites and web applications occupy the same “ecological niche”. Both of them are under the same influence of the environment, which consists of a variety of networks and devices. Such restrictions will not disappear if we decide to call what we are developing an “application”, and our users’ devices will not magically become much faster if we call the “site” an “application”.
It is our responsibility to find out who uses what we create, we must take into account the fact that the conditions under which different users connect to the Internet may differ from those we rely on. When creating something, we must know the goal for the sake of which we are creating it, and after that we should develop what helps to achieve this goal - even if the development turns out to be not such an exciting undertaking .
This means the need to reevaluate our dependence on JavaScript, and how its use, in particular to the detriment of HTML and CSS, can lead us to the use of irrational patterns that harm the performance and accessibility of web projects.
I witnessed the discovery of strange things in codebases when I worked with teams depending on frameworks in order to help them be more productive. Many of these finds have one thing in common, which is that the way they are written often leads to problems with the availability and performance of sites. For example, consider the following React component:
Here you can find several notable issues regarding project accessibility:
Considering the above, we refactor the component code:
Now, the fact that this component renders not only turns out to be more accessible, but less JS code is used to implement the same functionality as before. In a world that literally drowned in JavaScript, getting rid of a few lines of code should be seen as something positive. The browser gives us a lot of opportunities , and we need to strive to use these opportunities as often as possible.
I do not want to say here that problems with accessibility of pages arise exclusively when using certain frameworks. I mean, relying too much on JavaScript, the developer, as a result, will simply miss out on many important HTML and CSS features. These gaps in knowledge often lead to errors, moreover, we do not even suspect these errors. Frameworks can be useful tools that increase developer productivity, but the constant study of the capabilities of basic web technologies is extremely important in creating convenient, usable products, regardless of the auxiliary tools used in their development.
Since we are talking about frameworks, it should be noted that the web platform, in itself, is also a huge framework. As shown in the previous section, we find ourselves in a better position if we can rely on established patterns for working with markup and browser capabilities. An alternative to these standard features is to invent them again. Needless to say, such “invention” is fraught with considerable difficulties. But what if such problems, each in its own way, would be solved by the authors of all the JavaScript packages we install?
One of the weaknesses of developers that they can easily afford is the use of the Single Page Application (SPA) model, even in those projects for which this model is not suitable. Of course, such projects benefit from the fact that they are perceived by users as more productive due to routing performed by the client. But what are the disadvantages of using the SPA model? The browser’s built-in page navigation capabilities, although built on a synchronous model, give the project a ton of advantages. One of them is that the management of the history of visits is carried out through the implementation of complex specifications . Users without JavaScript, whether they disabled it themselves or notwill not lose the opportunity to work with the project. In order for a one-page application to be available in browsers with JavaScript turned off, it suddenly turns out that considerable attention needs to be paid to server rendering.
Comparison of different options for loading an experimental application on a slow communication channel. The rendering of the application on the left is completely dependent on JavaScript. The application on the right is rendered on the server, but then uses the hydrate () method on the client to connect the components to the markup already created on the server.
Here you can see that the application that is rendered on the client shows a blank screen for a few seconds, and then displays the finished one interface.
An application that is rendered on the server and rendered operational on the client quickly displays the main elements of the interface, but you can use it after about the same time as the application that is rendered entirely on the client.
The availability of the application also suffers if the router located on the client cannot inform the user about what has changed on the page he is viewing. This can force the user to rely on assistive technologies in order to find out what exactly has changed on the page, as a result, the user’s work with the site is much more complicated.
Further, you can immediately meet our old enemy - an excessive load on the system. Some client routers are very small. But if you are doing a project on React , use a compatible router , and possibly a libraryTo manage the state of the application, this means that you have to accept that it will contain a certain amount of service code, from which you can’t get anywhere. Namely, in this case it is approximately 135 Kb of such code. Carefully analyze the projects you are creating and whether the client routing is worth the additional load on the system. It usually happens that it is better to refuse the client routing system.
If you’re worried about the user’s experience, if you want the site to seem fast, you can rely on the rel = prefetch link attribute, which allows you to organize advance download of documents from the same source. Using this attribute has a huge impact on improving the performance of the project, perceived by users, since the pages linked to using this attribute, when you click on these links, are instantly loaded from the cache. In addition, since preloading data has a low priority, it is unlikely to compete for bandwidth with important resources.
The HTML code referenced by writing / is preloaded when you visit the main page of the site. When the user clicks on the corresponding link, the HTML code is instantly loaded from the browser cache. The
main problem that may arise with pre-loading pages, and which you need to be aware of, is that such a download can be a waste of time and resources. To solve it, you can, for example, use the small Quicklink script from Google, which mitigates this problem. It checks whether the current client is using a slow connection, whether it has data saving mode enabled , and, by default, allows you to avoid preloading materials from sources other than the page source.
In order to make the site look fast in the eyes of users who visit it many times, you can use service workers . They can be used regardless of whether the project uses a client routing system or not, given that you are familiar with some of the features of service workers. Performing route cachingby means of service workers, we get many of the same advantages that are typical for pre-loading materials of some links, but we have at our disposal much more extensive capabilities for working with requests and answers. Whether you perceive your site as an “application” or not, equipping it with a service worker is probably an example of one of the most critical JavaScript use cases of our time.
If we install a JS package designed to solve problems related to page layouts, then it's time for us to be very careful and ask ourselves what we are trying to achieve with this package. CSS was created specifically for building page layouts, in order to use it effectively, you do not need any abstractions. Most of the tasks of building layouts that they try to solve using JavaScript, such as placing elements, aligning them, adjusting their sizes, like managing text or even completely forming layoutsJavaScript means these days can be solved using CSS. Modern tools for creating layouts like Flexbox and Grid are well supported by browsers, so we don’t need to develop projects based on frameworks for working with layouts. By the way, CSS is also a framework. When at our disposal there is such an opportunity as property requests , the progressive improvement of layouts to support new means of their formation, as it turns out, is not so difficult .
Using JavaScript to solve the problems of creating page layouts and customizing their appearance is not news. This is what we did in 2009, when we lived in an atmosphere of self-deception, saying that every site should look like in IE6 as well as in more advanced browsers of that time. If today, in 2019, we continue to develop sites so that they look the same in all browsers, this means that we need to reconsider our goals. There will always be some browsers that need to be supported, and which do not have the same capabilities as the most modern browsers. The complete external similarity of projects on all platforms is not only a waste of energy, it is also a fundamental enemy of the idea of progressive improvements .
Do not get me wrong, I do not belong to the enemies of JavaScript. Thanks to this language, I have built a career, and, to be honest, JavaScript, for more than ten years, brings me a lot of pleasure. As with any long-term relationship, the more time I spend working with JavaScript, the better I get to know it. It is a mature language with many features, which, every year, is getting better.
However, sometimes it seems to me that something went wrong with our JavaScript relationship. I criticize him. Or, more precisely, I criticize the current tendency to consider JavaScript the main tool for site building, which is resorted to in the first place, without looking at anything else. When I analyzed another bundle that looked like a confusing Christmas garland, it became clear to me that the web was intoxicated with JavaScript. We resort to this language for almost any reason, even in cases where circumstances do not require this. Sometimes I think about how severe the consequences of this attitude towards JS can be.
I plan to continue to write about JavaScript and web development, to continue to look for ways to rationally use web technologies. Hopefully together we make the modern web better.
Dear readers! Do you think the modern web is really overloaded with JavaScript code?
If the server sends 400 KB of compressed JS code to the client, then the actual amount of code that the browser needs to process after decompressing the received data will be in the megabyte area. How well different devices handle this kind of work depends on the devices themselves. Much has been written about this , but we can only say with certainty that the time required even to parse the amount of code that is quite usual for its time varies greatly between different devices.
Take a look, for example, at thismy simple project. During page loading, about 23 Kb of uncompressed JS code is transferred to the client. Chrome, running on the MacBook Pro, which was released in mid-2017, processes this rather small amount of code in about 25 ms. On the Nokia 2 Android smartphone , however, a similar figure expands to 190 ms. This is not to say that it is very small, but in any case, the page becomes interactive quickly enough.
Now, an important question. What do you think, how does a simple Nokia 2 smartphone manage average modern pages? In fact - just awful. Browsing web pages, even on a fast Internet connection, forces the user to exercise patience, since working with pages loaded with JavaScript code becomes possible only after a hefty waiting period.
Performance overview of Nokia 2 when viewing a page containing a large amount of JS code, processing of which blocks the main stream.
Although the devices with which they use to view web pages and the networks through which data is transmitted have significantly improved in recent years, studies show that all these improvements are "eaten up" by large amounts of JS-code included in the pages. We need to use JavaScript responsibly. Responsibility begins with an understanding of what we are creating and how we do it.
Comparison of the ideology of "sites" and "applications"
Strange things happen with inaccurate terms that we use to name something, although their meanings, on an intuitive level, are clear to everyone. Sometimes we overload the meaning of the word “bee”, calling it “bees” and wasps, even though the difference between bees and wasps is very significant. Taking into account such differences can lead to the fact that the “bees” and “wasps” will act differently. For example, we are going to destroy a hornet’s nest, but if we are talking about bees, insects are much more useful and vulnerable, their nest, located in the wrong place, will probably be decided not to destroy, but to transfer it somewhere.
Similar freedom can be observed in the way we use the terms “website” and “web application”. The differences between these concepts are much less obvious than the differences between real wasps and honey bees, but if these concepts are combined, this can lead to very unpleasant consequences. Troubles begin when we allow ourselves something, depending on whether a project is “just a website” or “a full-blown web application”. If you are creating an information site for a company, then most likely you will not rely on a powerful framework for managing DOM changes or for implementing routing on the client. At a minimum, I hope so. Using tools that are poorly suited to solve certain problems will not only harm those who will use the site, but also, probably
When developing a web application, everything looks different. We install packages, which is accompanied by the addition of hundreds, if not thousands, of dependencies to the project. Moreover, we are not even sure of the safety of some of them. We write complex configurations for bundlers. When working in such a ubiquitous crazy development environment, you need knowledge and attention in order to make sure that what was collected is quick, that the project will work where it should work. If in doubt, run the npm ls --prod command in the root directory of your project and see if you can name the purpose of using all of that.that this command will output. Even if you can do it, this does not apply to third-party scripts. I am sure several such scripts are also used in your project.
We forget that both websites and web applications occupy the same “ecological niche”. Both of them are under the same influence of the environment, which consists of a variety of networks and devices. Such restrictions will not disappear if we decide to call what we are developing an “application”, and our users’ devices will not magically become much faster if we call the “site” an “application”.
It is our responsibility to find out who uses what we create, we must take into account the fact that the conditions under which different users connect to the Internet may differ from those we rely on. When creating something, we must know the goal for the sake of which we are creating it, and after that we should develop what helps to achieve this goal - even if the development turns out to be not such an exciting undertaking .
This means the need to reevaluate our dependence on JavaScript, and how its use, in particular to the detriment of HTML and CSS, can lead us to the use of irrational patterns that harm the performance and accessibility of web projects.
Do not let frameworks impose irrational patterns on you
I witnessed the discovery of strange things in codebases when I worked with teams depending on frameworks in order to help them be more productive. Many of these finds have one thing in common, which is that the way they are written often leads to problems with the availability and performance of sites. For example, consider the following React component:
import React, { Component } from "react";
import { validateEmail } from "helpers/validation";
class SignupForm extends Component {
constructor (props) {
this.handleSubmit = this.handleSubmit.bind(this);
this.updateEmail = this.updateEmail.bind(this);
this.state.email = "";
}
updateEmail (event) {
this.setState({
email: event.target.value
});
}
handleSubmit () {
// если адрес почты проходит проверку - отправить данные
if (validateEmail(this.state.email)) {
// ...
}
}
render () {
return (
Enter your email:
);
}
}
Here you can find several notable issues regarding project accessibility:
- A form that does not use an element
- The tag is
not a substitute for the tag
, which gives some opportunities regarding the availability of projects that are not available
.
- Element
- By the way, why use JavaScript to verify email addresses, while HTML5 puts at our disposal controls that support checking input data in almost all browsers - up to IE10? Here we see a missed opportunity to take advantage of the functionality that is already in the browser and apply the appropriate element type , as well as the required attribute . However, using such constructions, keep in mind that setting up their normal interaction with screen readers will require some effort .
Considering the above, we refactor the component code:
import React, { Component } from "react";
class SignupForm extends Component {
constructor (props) {
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit (event) {
// Нужно в том случае, если мы отправляем данные на сервер с использованием XHR
// (но будет работать и в том случае, если страница рендерится на сервере, а в браузере отключён JS).
event.preventDefault();
// Продолжаем работу…
}
render () {
return (
);
}
}
Now, the fact that this component renders not only turns out to be more accessible, but less JS code is used to implement the same functionality as before. In a world that literally drowned in JavaScript, getting rid of a few lines of code should be seen as something positive. The browser gives us a lot of opportunities , and we need to strive to use these opportunities as often as possible.
I do not want to say here that problems with accessibility of pages arise exclusively when using certain frameworks. I mean, relying too much on JavaScript, the developer, as a result, will simply miss out on many important HTML and CSS features. These gaps in knowledge often lead to errors, moreover, we do not even suspect these errors. Frameworks can be useful tools that increase developer productivity, but the constant study of the capabilities of basic web technologies is extremely important in creating convenient, usable products, regardless of the auxiliary tools used in their development.
Rely on the power of the web platform and give your projects a bright future
Since we are talking about frameworks, it should be noted that the web platform, in itself, is also a huge framework. As shown in the previous section, we find ourselves in a better position if we can rely on established patterns for working with markup and browser capabilities. An alternative to these standard features is to invent them again. Needless to say, such “invention” is fraught with considerable difficulties. But what if such problems, each in its own way, would be solved by the authors of all the JavaScript packages we install?
▍Single Page Applications
One of the weaknesses of developers that they can easily afford is the use of the Single Page Application (SPA) model, even in those projects for which this model is not suitable. Of course, such projects benefit from the fact that they are perceived by users as more productive due to routing performed by the client. But what are the disadvantages of using the SPA model? The browser’s built-in page navigation capabilities, although built on a synchronous model, give the project a ton of advantages. One of them is that the management of the history of visits is carried out through the implementation of complex specifications . Users without JavaScript, whether they disabled it themselves or notwill not lose the opportunity to work with the project. In order for a one-page application to be available in browsers with JavaScript turned off, it suddenly turns out that considerable attention needs to be paid to server rendering.
Comparison of different options for loading an experimental application on a slow communication channel. The rendering of the application on the left is completely dependent on JavaScript. The application on the right is rendered on the server, but then uses the hydrate () method on the client to connect the components to the markup already created on the server.
Here you can see that the application that is rendered on the client shows a blank screen for a few seconds, and then displays the finished one interface.
An application that is rendered on the server and rendered operational on the client quickly displays the main elements of the interface, but you can use it after about the same time as the application that is rendered entirely on the client.
The availability of the application also suffers if the router located on the client cannot inform the user about what has changed on the page he is viewing. This can force the user to rely on assistive technologies in order to find out what exactly has changed on the page, as a result, the user’s work with the site is much more complicated.
Further, you can immediately meet our old enemy - an excessive load on the system. Some client routers are very small. But if you are doing a project on React , use a compatible router , and possibly a libraryTo manage the state of the application, this means that you have to accept that it will contain a certain amount of service code, from which you can’t get anywhere. Namely, in this case it is approximately 135 Kb of such code. Carefully analyze the projects you are creating and whether the client routing is worth the additional load on the system. It usually happens that it is better to refuse the client routing system.
If you’re worried about the user’s experience, if you want the site to seem fast, you can rely on the rel = prefetch link attribute, which allows you to organize advance download of documents from the same source. Using this attribute has a huge impact on improving the performance of the project, perceived by users, since the pages linked to using this attribute, when you click on these links, are instantly loaded from the cache. In addition, since preloading data has a low priority, it is unlikely to compete for bandwidth with important resources.
The HTML code referenced by writing / is preloaded when you visit the main page of the site. When the user clicks on the corresponding link, the HTML code is instantly loaded from the browser cache. The
main problem that may arise with pre-loading pages, and which you need to be aware of, is that such a download can be a waste of time and resources. To solve it, you can, for example, use the small Quicklink script from Google, which mitigates this problem. It checks whether the current client is using a slow connection, whether it has data saving mode enabled , and, by default, allows you to avoid preloading materials from sources other than the page source.
In order to make the site look fast in the eyes of users who visit it many times, you can use service workers . They can be used regardless of whether the project uses a client routing system or not, given that you are familiar with some of the features of service workers. Performing route cachingby means of service workers, we get many of the same advantages that are typical for pre-loading materials of some links, but we have at our disposal much more extensive capabilities for working with requests and answers. Whether you perceive your site as an “application” or not, equipping it with a service worker is probably an example of one of the most critical JavaScript use cases of our time.
▍JavaScript is not designed for layout
If we install a JS package designed to solve problems related to page layouts, then it's time for us to be very careful and ask ourselves what we are trying to achieve with this package. CSS was created specifically for building page layouts, in order to use it effectively, you do not need any abstractions. Most of the tasks of building layouts that they try to solve using JavaScript, such as placing elements, aligning them, adjusting their sizes, like managing text or even completely forming layoutsJavaScript means these days can be solved using CSS. Modern tools for creating layouts like Flexbox and Grid are well supported by browsers, so we don’t need to develop projects based on frameworks for working with layouts. By the way, CSS is also a framework. When at our disposal there is such an opportunity as property requests , the progressive improvement of layouts to support new means of their formation, as it turns out, is not so difficult .
/* Тут будут стили, рассчитанные, в первую очередь, на мобильные устройства и не пользующиеся возможностями CSS Grid. */
/* Правило @supports игнорируется браузерами, которые не поддерживают технологию CSS Grid, или не поддерживают это правило. */
@supports (display: grid) {
/* Стили для более крупных экранов */
@media (min-width: 40em) {
/* Сюда попадают прогрессивно улучшаемые стили для CSS Grid */
}
}
Using JavaScript to solve the problems of creating page layouts and customizing their appearance is not news. This is what we did in 2009, when we lived in an atmosphere of self-deception, saying that every site should look like in IE6 as well as in more advanced browsers of that time. If today, in 2019, we continue to develop sites so that they look the same in all browsers, this means that we need to reconsider our goals. There will always be some browsers that need to be supported, and which do not have the same capabilities as the most modern browsers. The complete external similarity of projects on all platforms is not only a waste of energy, it is also a fundamental enemy of the idea of progressive improvements .
Bottom line: I'm not going to become a JavaScript killer
Do not get me wrong, I do not belong to the enemies of JavaScript. Thanks to this language, I have built a career, and, to be honest, JavaScript, for more than ten years, brings me a lot of pleasure. As with any long-term relationship, the more time I spend working with JavaScript, the better I get to know it. It is a mature language with many features, which, every year, is getting better.
However, sometimes it seems to me that something went wrong with our JavaScript relationship. I criticize him. Or, more precisely, I criticize the current tendency to consider JavaScript the main tool for site building, which is resorted to in the first place, without looking at anything else. When I analyzed another bundle that looked like a confusing Christmas garland, it became clear to me that the web was intoxicated with JavaScript. We resort to this language for almost any reason, even in cases where circumstances do not require this. Sometimes I think about how severe the consequences of this attitude towards JS can be.
I plan to continue to write about JavaScript and web development, to continue to look for ways to rationally use web technologies. Hopefully together we make the modern web better.
Dear readers! Do you think the modern web is really overloaded with JavaScript code?