Thoughts on loading JavaScript Modules 2

Source: Internet
Author: User
Tags try catch

After several days of thinking, I think of a question called "files and modules. Our modules must be written in a JS file. These modules can be divided into core modules and peripheral modules. Of course, the core module is written in the main file. It should contain the most important logic, loaders, queues, namespaces constructors, and so on. However, if a file only has one module, this is a waste of resources and will lead to too many requests. Therefore, multiple modules "coexist" with one file. In the non-core modules of the main file, I call it internal modules. There is no difference between other incircle and peripheral, but the file is different. For the sake of convenience, do not rely on Peripheral modules for internal modules!

But when we use the script tag to reference the JS file, it will execute the script in it. The main logic can be parsed with no worries. However, for internal modules, their logic is put into a function body, and the control flow can only pass over them, and cannot touch anything in it. This module name and callback function and related configuration will enter a processing function (hereinafter referred to as use), and then put it into a processing queue. If a dependency exists, check whether the file where the dependency module is located is loaded. If the dependency module is not, load the file. If the dependency module is loaded, check that the module has been assembled into the framework namespace, finally, execute the callback function.

According to the above analysis, the operations can be divided into several types: file loading, Module assembly, and execution callback. They can only be executed in sequence. Looking at most of the class library frameworks, the solution is these two types: Dynamic script insertion and Ajax callback parsing.

    • Dynamic script insertion generates a Script node, sets its target SRC, and inserts it into the head node. The reason for not using document. Write is to insert it into the body, and there are many defects. For details, refer to my article.
    • Ajax callback parsing uses the XMLHTTP object to parse the responsetext returned by the request. Then, the script is used to parse the program eval(standard browser or window.exe cscript (IE), or create another script tag for parsing. It can be seen that this method needs to deal with many compatibility issues, and another cross-domain issue .......

My position is obvious. Use the first one. However, the script tag still has many problems with callback processing.

 var script = Dom. genscriptnode (); script. src = URL Dom. head (). appendchild (SCRIPT); script. onload = script. onreadystatechange = function () {If ((! This. readystate) | this. readystate = "loaded" | this. readystate = "complete") {If (! Dom. done [name]) {alert ("loading failed 1") Dom. head (). removechild (SCRIPT)} callback () ;}} script. onerror = function () {script. onload = script. onerror = undefined; alert ("loading failed 2") Dom. head (). removechild (SCRIPT)} 

If the JS file referenced by our script tag does not exist, the onerror event will be triggered in some standard browsers, but there is no onload event or onerror event in IE, we cannot determine whether the file has been successfully loaded. We only have to assume that if the target file is successfully loaded, Dom. done. modulename is true. If it fails, it is undefined! Dom. DONE [name] is true, removing this useless script tag. This method should be perfect and compatible with IE and standard browsers. Unfortunately, standard browsers are not just stones, but they are still different. The hateful opera will throw a fatal error when loading fails, and the try catch is useless. Therefore, this URL must be absolutely correct. Therefore, we need to introduce the real URL mechanism.

Whether it's dojo, JSAN (the most prestigious module loading framework in earlier years), or Yui, let alone using. JS, require. JS, packages. JS and other niche class libraries all have a mechanism to convert module names (Package Names) to URLs. For example:

 
"Query" ===> "http: // localhost: 3000/javascripts/DOM/query. js"

Http: // localhost: 3000/javascripts/I call it basepath. It is the path of the JS file where the core module is located. Dom is forcibly added. All peripheral module files must be here, and query is the module name. For details about how to obtain the JS file path, refer to my blog. In extreme cases, sometimes we have to discard this game rule and the framework cannot find the correct URL. Then we explicitly point out its path by adding a parentheses in the module name, it is the actual URL.

VaR module = "dom. "+ item, URL; // process Dom. node (http://www.cnblogs.com/rubylouvre/dom/node.js) Case VaR _ u = module. match (/\ ([^)] +) \)/); url = _ u & _ u [1]? _ U [1]: Dom. getbasepath () + "/" + module. replace (/\. /g, "/") + ". JS "; var script = Dom. genscriptnode (); script. src = URL Dom. head (). appendchild (SCRIPT); var scope = Dom. namespace (module, true )//..........

Because the modules and callback functions are the same in my ideas, they are all callback functions of the same method. I name this method "use", but it is the responsibility of adding and using part-time yui3. For example, this is a peripheral module query:

// Located in a separate file/DOM/query. dom in Js. use ("query", function () {arguments. callee. _ attached = true; Dom. query = function (selector, context) {context = context | document try {var els = context. queryselectorall (selector); Return Dom. filter (ELS, function (EL) {return el. nodetype = 1})} catch (e) {alert ("your browser does not support queryselectorall") }}, {use: ["Collection"]});

It depends on another peripheral module collection:

// Located in a separate file/DOM/collection. dom in Js. use ("Collection", function () {arguments. callee. _ attached = true; Dom. filter = function (array, FN, scope) {var result = [], rI = 0; For (VAR I = 0, n = array. length; I <n; I ++) {If (fn. call (scope | array [I], array [I], I, array) {result [ri ++] = array [I] ;}} return result ;} dom. each = function () {/**/} Dom. map = function () {/**/} Dom. keys = function (){/**/}//.....})

The following code is called on the webpage:

 
Dom. ready (function () {Dom. use ("query", function () {var els = Dom. query ("p") Alert (ELS )});});

How to distinguish between them, because callback functions are called infinitely, while modules are not allowed. Otherwise, some important configurations may be modified and they can only be executed once. We need something to identify it as a module. The following is a method I have come up:

Dom. use ("Collection", function () {arguments. callee. _ attached = true; Dom. filter = function () {/**/} Dom. each = function () {/**/} Dom. map = function () {/**/} Dom. keys = function (){/**/}//.....})

When this function is executed once, it has a static attribute. If it appears again in the queue next time, we will detect it and skip it:

 
If (! FN. _ attached) {// if it is a module, only FN ();} is executed once ();}

This is also true for files. If this JS file has been loaded, we do not need to load it any more. Therefore, we can use a hash to store this message.

 
Dom. loaded. collection = true; Dom. use ("Collection", function () {arguments. callee. _ attached = true; Dom. filter = function () {/**/} Dom. each = function () {/**/} Dom. map = function () {/**/} Dom. keys = function (){/**/}//.....})

This is basically the case. Let me review some concepts. The core module, an important component of the framework, is certainly not in the use function. On the contrary, the use function, processing queues, feature detection, and other important things are all part of the framework. Inner circumference module, which is located in the same JS file as the core module and should not depend on Peripheral modules. Peripheral module, which can be dependent on other peripheral modules. Because it must be made up of core modules and internal modules, these items already exist during peripheral loading, therefore, we do not need to write out these internal dependencies. You only need to list the peripheral modules, because it is still unknown whether the files they are located are loaded. The processing queue is just a common array. The elements in it can be the module name, the module itself and the callback function..

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.