Why is web page modularization required ?, Need web page modularization?
This article discusses why Web modularization is useful and introduces some mechanisms that can be used to implement Web modularization. Another article introduces the design concept of function packaging format used by RequireJS.
Question 1
Websites are gradually transformed into Web apps
Code complexity is gradually improved
Difficulty in assembling and changing
JS files/modules to be separated by developers
Code can be optimized to several HTTP requests during deployment.
Solution § 2
Front-end developers need such solutions:
Some of these Apis # include/import/require
Ability to load nested Dependencies
It is easy to use for developers and supports optimization tools in the future to facilitate deployment.
Script Loading API § 3
First, sort out the Script Loading API. There are several options:
Dojo: dojo. require ("some. module ")
LABjs: $ LAB. script ("some/module. js ")
CommonJS: require ("some/module ")
All are mapped to load some/path/some/module. js. Ideally, we can choose the CommonJS syntax, because it is likely to become more common and we want to reuse code.
At present, we also hope some syntaxes can load existing plain text JavaScript files, so developers do not have to rewrite all JavaScript to benefit from Script Loading.
However, we need something that can work better in browsers. The require () of CommonJS is a synchronous call, which is expected to return to that module immediately. However, this does not work well in browsers.
Asynchronous and synchronous 4
The following example illustrates the basic problems of the browser. Suppose we have an Employee object, and we want a Manager object derived from the Employee object. To get this example, we may use our step loading API to encode it like this:
123 |
var Employee = require( "types/Employee" ); function Manager () { this .reports = []; } //Error if require call is asyncManager.prototype = new Employee(); |
As shown in the preceding annotations, if require () is asynchronous, this code will not work. However, synchronous loading in the browser will erase the performance. So what should we do?
Script Loading: XHR § 5
Loading scripts using XMLHttpRequest (XHR) is very attractive. If XHR is used, we can touch the above text, that is, we can use a regular expression to find require () calls, to ensure that we have loaded these scripts, and then use eval () or the script element transmits the text content to the script loaded using XHR.
It is not good to use eval () to evaluate the module:
The developer has been told that eval () is not easy to use.
Some environments do not support eval ().
Difficult to debug. Firebug and WebKit check servers have a // @ sourceURL = Convention to name the evaluated text. However, this feature is not supported by all browsers.
Different browsers evaluate different context environments. ExecScript in IE may be available, but it also means more moving parts.
It is not good to set the script tag with text content to the file text:
XHR still has problems with cross-origin requests. Some browsers now support cross-origin XHR, but not all of them. In addition, IE decides to create a different API object: XDomainRequest to implement cross-origin requests. There are more places to change, making it easier to make mistakes. In particular, you need to be sure not to send any nonstandard HTTPheader or another "pre-check" request to ensure that this cross-origin request is allowed.
Dojo uses XHR-based loader through eval (), but although it can be used, it has always been the source of troubles for developers. Dojo has an xdomain loader, but it needs to use a function wrapper to modify the require module. Therefore, the script src = "" tag can be used to load the module. There are also many boundaries and changes to increase the difficulty for programmers.
If we create a new script loader, we can do better.
Script Loading: Web Workers § 6
Web worker may be another method for loading scripts,:
It has poor cross-platform performance.
It is a message passing API, and the script may need to interact with DOM. It only uses worker to obtain the script text, then transmits the text to the main window, and then uses eval/script to execute the script. This method carries all the XHR problems mentioned above.
Script Loading: document. write () § 7
Document. write () can be used to load the script. It can load the script from other domains and map to how the browser usually uses the script, so it can be used for simple debugging.
However, in the asynchronous VS synchronization example, we cannot directly execute the script. Ideally, before executing the script, we can use require () to know the relevant dependencies and ensure that these dependencies are first loaded. But we cannot access it before the script is executed.
Moreover, document. write () does not work after loading the page. A good way for your website is to load the script when the user needs to perform the next operation.
Finally, load the script or block page rendering through document. write. This method is not advisable for your website to have the best performance.
Script Loading: head. appendChild (script) § 8
We can create scripts as needed and add them to the header:
12345 |
var head = document.getElementsByTagName( 'head' )[0], script = document.createElement( 'script' ); script.src = url; head.appendChild(script); |
The above script snippets have a little more, but that is the basic idea. This method is better than document. write because it does not block page rendering and can still work after the page is loaded.
However, it still has the problem of synchronous VS asynchronous examples: Ideally, before executing the script, we can know the relevant dependencies through require () and ensure that these dependencies are first loaded.
Function encapsulation § 9
Before executing our script, we need to know the relevant dependencies and ensure that they have been loaded. The best way to do this is to construct our module loading API through function encapsulation. Like this:
1234567891011121314 |
define( //The name of this module "types/Manager" , //The array of dependencies [ "types/Employee" ], //The function to execute when all dependencies have loaded. The //arguments to this function are the array of dependencies mentioned //above. function (Employee) { function Manager () { this .reports = []; } //This will now work Manager.prototype = new Employee(); //return the Manager constructor function so it can be used by //other modules. return Manager; } ); |
This is the syntax of ReguireJS. If you want to load JavaScript that is not defined as a module's plain text, there is a simple Syntax:
123 |
require([ "some/script.js" ], function () { //This function is called after some/script.js has loaded. }); |
This syntax is selected because it is concise enough and allows the loader to use the head. appendChild (script) Loading type.
It is different from common CommonJS syntaxes for the good work in browsers. It is recommended that the common CommonJS syntax use the loading type of head. appendChild (script). If the server process has encapsulated functions, the module can be converted to the transmission format.
I believe that it is important not to force a running server process to convert code:
First, debugging is quite weird, because when the server injects an encapsulated function, the row number of the source file will be disabled.
Second, more work is required. Frontend development should try to use static files.
More details about the power of the design and the use cases of functional encapsulation formats are called Asynchronous Module Definition (AMD). Why is AMD?
Address: http://requirejs.org/docs/why.html