Report by Andrei Sumin ( habraprofil ) “ How not to drown in megabytes of JS-code? "- another in a series of transcripts from the Mail.Ru Technology Forum 2011 . For details on how the report decryption system works, see the article “Reverse” of the Mail.Ru Technologies Forum: High-tech in event-management . There, as well as on the Forum website ( http://techforum.mail.ru ) - links to transcripts of other reports.
( Download video version for mobile devices - iOS / Android H.264 480? 368, size 170 Mb, video bitrate 500 kbps, audio - 64 kbps)( Download video version of higher resolution H.264 624? 480, size 610 Mb, video bitrate 1500 kbps, audio - 128 kbps)( Download presentation slides, 4.7Mb)
I will say right away that in this post there will not even be a mention of the latest "chips" embedded by browsers. Moreover, I covered this topic for the first time in 2007. I will tell you about some of the methods of organizing the code, which for 5 years now have helped me and my colleagues successfully develop projects with a lot of JS code.
Let's go back a little, around 2002. Sites then contained little JS code. For the most part, Javascript was made with small “ryushechki”, like changing the background by hovering. The project structure was simple and transparent.
')

Since 2005, we have seen rapid development, and already then, vacancies with the title “javascript programmer” appear in RuNet. Projects have also become a bit more complicated.

I singled out common.js not because it is so important, but because it has become big and uncontrollable. If not one person worked, but a team, everyone would write something different there, at the end of the file. Support for the project, of course, complicated.

As a result, we have confusion, a huge file and, the worst thing, in my opinion - there is no code reuse.
Specifically, I had this: some functions for escaping strings, for example, html, no one else then knew how to do that. You come to the project or take the project of another person, you see the function of escaping, you try to apply it, it does not work. Either the bugs, or the wrong escape, all that is needed, or the extra escape. It all ended with those (nobody knew for sure about the tests) that I was very afraid to change this function, and just wrote another one next to it. After some time, I thought, well, wherever I remembered, I changed it to my own, and it’s definitely better, faster, there are no bugs in it, and, like, you can delete the old one. But at the last moment the hand trembles, okay leave. So this code is for future generations.

The following steps were obvious: people just began to divide one large file for some logical parts. And well, if by logical - usually came out "as it will."

And let's be frank - this, in fact, did not solve the problems. The size remained, only earlier it was one file, and now it is a folder. We have new problems - connection problems. If we hit several files, naturally, we want that on pages where some part of the files are needed, we only include this part of the files. This problem had to be solved somehow. And the problem with the maintenance of the connection, because in fact it turned out like this: on all pages they connected all the scripts.
The next slide is very important and reflects the main idea of my report.

The idea is as follows. Yes, we have a lot of JavaScript, but it is somehow broken, but we need to connect part of it on the pages according to some rules. Let the resulting HTML, which is the result of working out all our logic, will be the config of what needs to be connected.
I will explain. We have a div tag, which includes some complete block - let's say it will be a list of folders, i.e., in this div is a list of folders. The first step, we mark with a class - this div is a component. This means that the js engine will search for it by this mark. The second line is onclick, return is specified there, and some hash. This hash contains a description of what this component is.
As a result, we need to find the component in the DOM tree. Determine what this component is (in my case, the type information is in onclick). Connect js-files to make it all work.
The first problem is solved, at least in modern browsers, very easily. CSS selectors work a lot where natively, and where not natively, you have the appropriate libraries at your disposal.
Now the most interesting part is what is written in onclick. There you can sew any information that you need for initialization. In my case, this is the type of component, I understand from the contents of the hash that this is a component for working with folders. To get it is very easy.

Thus, we immediately get a hash with the input data for the component.

Require - this is the same function - the heart that will make our entire circuit work. Naturally, it is much more difficult at some production solution, but this does not change the ideas.

This require is written in some library, in some component, that is, in some javaScript file that is responsible for the functionality. The javascript file with its help tells the kernel that for my work I need file1 and file2. This is passed to the first argument, and the second argument to the kernel is the function that will be executed after it loads both.
A very important point. The function says loaded (file). Naturally, the idea has long been new, of course, there are implementations, in addition to the one that I describe. But in some implementations there is one difference, they try to understand that the functionality is loaded by some metadata. Suppose the onload event is triggered by a script or something like that. I basically did not do this: the code that is in javascript, calling the method loaded, he will say for sure that I am ready. And not because there is something loaded, not because someone thinks that I loaded. Yes, I booted up, I definitely got what I needed, I’m definitely ready. If I call on the chain, who needs me further, then we can safely say about it and not be afraid of anything.

Here is how it looks on a small bundle. Folders need libraries to work with dates.

In the library for working with dates, strings are needed to display nicely, for example, some implementation of printf is in strings. And strings are self-sufficient, they do not need anything. And we have a require chain. In folders.js, we ask for dates, as we load the dates, we call a function in which the folders themselves tell the kernel that I have dates, I don’t need anything, I’m ready to go. Dates have the same strings. And strings do not need anything when they are loaded, they say at the end - everything, we loaded, let's work on.
We reviewed the complete set of tasks to make our example work.

First of all, we extract from the DOM tree all the components that are needed. The second stage determines what this component is, in the hash we will have a component for work, let's say that this is a component for working with the list of letters. Further require function, here there is the first argument of getFileName (type). By line, the kernel can understand the real path to the file in order to write the script tag in src. Accordingly, in our case, this will be folders.js. Script folders will be loaded. He will say in require that I need dates, dates will say that I need strings. 3 script tags are generated, in the reverse order, the loaded ones will work and as a result we have a function that says window [type] .init (), it will be executed and the component will start to initialize.
But it is too early to rest, we got another problem. We have quite a load of isolated components, and imagine such a situation - everything seems to be fine. A manager comes to the developer and says: "I want you to make a calendar."

The developer says, here I will have a separate div, I will have a separate file. I have a library for working with strings, which is covered with tests with dates, a date that is covered with tests, and I make a calendar in 2 days. Shows the manager, he is happy, shows colleagues in other projects. They come again to you.

It seems to be the same calendar, but the number of interfaces that different people want for this beautiful licked thing is slightly depressing.

Then you have the following options: you can do a very long design, do abstractions, do abstractions over abstractions, but believe me, after three months, and if you are a brilliant programmer, after six months, another programmer will come to your place, he will be surprised .

We are all people, we all understand that everything is impossible to take into account, so there is no new pattern, it has been used in programming for a long time. Moreover, from the very beginning, with the advent of JavaScript, which is used to the full in browsers, these are events. You make the calendar, make it systemic, make it inviolable, but make it an event API.

It is very easily scaled, it is very easily covered with tests, and the programmer who came to write down his little thing is very easy and do not touch your code.
It would seem that everything is just fine now. We have a config in html, we have a download of components, by request, according to the html that is. We have an interface for communicating components with each other. But there was another problem.
If you know today, then tomorrow you don’t know the order of initialization of components. Imagine such a situation: met the calendar. He began to boot, booted, initialized. After initialization, I threw an event that I will now put on the date on November 7th. All he has already done, only after this, the DOM contains a small component that should be written on November 7th. He hangs on the event, and the event has already happened. He is no longer there.
The solution was from the server programming section, I was prompted. It exists a long time ago and is called - queues.

We add one more argument to the dispatch method, I highlighted it in red ,. This is the size of the queue. The calendar during its initialization makes dispatch, since we have a callback object. He tells him that the queue size of such events is one, i.e. if someone subscribes to a similar event and has not received anything yet, then he will receive events via the first in first out stack. The queue length will be equal to the size of the digit indicated on the last argument. And he, accordingly, receives all these events.
As for mail.ru, I have not been working here for a year, but for only 4 months, I thought that I would come with a long raincoat now, and show everyone here how to live. And on the very first day, when I saw the source code of JavaScript mail.ru I realized that they wrote almost the same thing. Mostly even to letters.
This text is based on the report of Sumin Andrei at the Mail.Ru 2011 Technology Forum , held on November 16 in the center of Infospace. Details about the technology of creating texts of reports based on video recordings can be found here: “Wrong side” of the Mail.Ru Technologies Forum: High-tech in event-management . Video versions of other reports (including versions for mobile devices) are available on the Forum website - techforum.mail.ru . Text versions of the reports will be published here and on the Forum website every week or less often in a similar format. Please report in the "lichku" about typos in the text.