Javascript modular programming (3): usage of require.js

Parts 1 and 2 of this series , which introduced Javascript module prototypes and theoretical concepts, today show how to put them into practice.

I'm using a very popular library require.js .

1. Why use require.js?

In the earliest days, all Javascript code was written in a file, and it was enough to load this file. Later, with more and more code, one file was not enough, and it had to be divided into multiple files and loaded in sequence. The following webpage code, I believe many people have seen it.

  <script src="1.js"></script>
  <script src="2.js"></script>
  <script src="3.js"></script>
  <script src="4.js"></script>
  <script src="5.js"></script>
  <script src="6.js"></script>

This code loads multiple js files in sequence.

This way of writing has a big disadvantage. First, when loading, the browser will stop the rendering of the web page. The more files are loaded, the longer the web page will lose its response. 1.js should be in front of 2.js), and the modules with the most dependencies must be loaded last. When the dependencies are complex, it will be difficult to write and maintain the code.

The birth of require.js is to solve these two problems:

  

  (1) Realize the asynchronous loading of js files to avoid the loss of response of web pages;

  (2) Manage dependencies between modules to facilitate code writing and maintenance.

2. Loading of require.js

The first step in using require.js is to go to the official website to download the latest version.

After downloading, assuming it is placed under the js subdirectory, it can be loaded.

  <script src="js/require.js"></script>

One might think that loading this file could also cause the web page to become unresponsive. There are two solutions, one is to load it at the bottom of the page, and the other is to write the following:

  <script src="js/require.js" defer async="true" ></script>

The async attribute indicates that this file needs to be loaded asynchronously to prevent the web page from becoming unresponsive. IE does not support this property, only defer, so write defer as well.

After loading require.js, the next step is to load our own code. Suppose our own code file is main.js, which is also placed under the js directory. Then, just write the following:

  <script src="js/require.js" data-main="js/main"></script>

The role of the data-main attribute is to specify the main module of the web program. In the above example, it is main.js under the js directory, and this file will be the first to be loaded by require.js. Since the default file extension of require.js is js, main.js can be abbreviated as main.

3. Writing the main module

The main.js in the previous section, I call it the "main module", which means the entry code for the entire web page. It's a bit like the main() function in C, where all the code starts to run.

Let's see how to write main.js.

If our code does not depend on any other modules, then we can write javascript code directly.

  // main.js

  alert("Successful loading!");

But in this case, there is no need to use require.js. The really common situation is that the main module depends on other modules, in which case the require() function defined by the AMD specification is used.

  // main.js

  require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){

    // some code here

  });

The require() function accepts two parameters. The first parameter is an array, indicating the modules it depends on. The above example is ['moduleA', 'moduleB', 'moduleC'], that is, the main module depends on these three modules; the second parameter is a callback function, the current It will be called after all the modules specified above are loaded successfully. Loaded modules are passed into the function as parameters, so they can be used inside the callback function.

require() loads moduleA, moduleB and moduleC asynchronously, and the browser will not lose response; the callback function specified by it will run only after the previous modules are loaded successfully, which solves the problem of dependencies.

Below, we look at a practical example.

Assuming that the main module depends on the three modules jquery, underscore and backbone, main.js can be written like this:

  require(['jquery', 'underscore', 'backbone'], function ($, _, Backbone){

    // some code here

  });

require.js will load jQuery, underscore and backbone before running the callback function. The code of the main module is written in the callback function.

Fourth, the loading of the module

In the last example in the previous section, the main module's dependent modules are ['jquery', 'underscore', 'backbone']. By default, require.js assumes that these three modules are in the same directory as main.js, with filenames jquery.js, underscore.js, and backbone.js, and loads them automatically.

Using the require.config() method, we can customize the loading behavior of the module. require.config() is written at the head of the main module (main.js). The parameter is an object whose paths property specifies the loading path of each module.

  require.config({

    paths: {

      "jquery": "jquery.min",
      "underscore": "underscore.min",
      "backbone": "backbone.min"

    }

  });

The above code gives the file names of the three modules, and the path defaults to the same directory as main.js (js subdirectory). If these modules are in other directories, such as the js/lib directory, there are two ways to write them. One is to specify the paths one by one.

  require.config({

    paths: {

      "jquery": "lib/jquery.min",
      "underscore": "lib/underscore.min",
      "backbone": "lib/backbone.min"

    }

  });

The other is to directly change the base directory (baseUrl).

  require.config({

    baseUrl: "js/lib",

    paths: {

      "jquery": "jquery.min",
      "underscore": "underscore.min",
      "backbone": "backbone.min"

    }

  });

If a module is on another host, you can also specify its URL directly, for example:

  require.config({

    paths: {

      "jquery": "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min"

    }

  });

require.js requires that each module is a separate js file. In this case, if multiple modules are loaded, multiple HTTP requests will be issued, which will affect the loading speed of the web page. Therefore, require.js provides an optimization tool . After the module is deployed, you can use this tool to combine multiple modules into one file to reduce the number of HTTP requests.

Five, AMD module writing

Modules loaded by require.js, using AMD specifications. That is, modules must be written as specified by AMD.

Specifically, the module must be defined using a specific define() function. If a module does not depend on other modules, it can be defined directly in the define() function.

Suppose there is now a math.js file that defines a math module. Then, math.js should be written like this:

  // math.js

  define(function (){

    var add = function (x,y){

      return x+y;

    };

    return {

      add: add
    };

  });

The loading method is as follows:

  // main.js

  require(['math'], function (math){

    alert(math.add(1,1));

  });

If this module also depends on other modules, the first parameter of the define() function must be an array indicating the module's dependencies.

  define(['myLib'], function(myLib){

    function foo(){

      myLib.doSomething();

    }

    return {

      foo : foo

    };

  });

When the require() function loads the above module, the myLib.js file is loaded first.

6. Loading non-standard modules

Theoretically, the module loaded by require.js must be a module defined by the define() function according to the AMD specification. But in fact, while some popular libraries (such as jQuery) already comply with AMD specifications, many more libraries do not. So, is require.js able to load non-canonical modules?

The answer is yes.

Before such modules are loaded with require(), some of their characteristics must be defined using the require.config() method.

For example, the underscore and backbone libraries are not written to AMD specifications. To load them, their characteristics must be defined first.

  require.config({

    shim: {

      'underscore':{
        exports: '_'
      },

      'backbone': {
        deps: ['underscore', 'jquery'],
        exports: 'Backbone'
      }

    }

  });

require.config() accepts a configuration object, which in addition to the paths attribute mentioned earlier, also has a shim attribute, which is specially used to configure incompatible modules. Specifically, each module should define (1) the exports value (the output variable name), indicating the name of the module when it is called externally; (2) the deps array, indicating the module's dependencies.

For example, a jQuery plugin can be defined like this:

  shim: {

    'jquery.scroll': {

      deps: ['jquery'],

      exports: 'jQuery.fn.scroll'

    }

  }

Seven, require.js plugin

require.js also provides a series of plugins that implement some specific functions.

The domready plugin allows the callback function to run after the page DOM structure is loaded.

  require(['domready!'], function (doc){

    // called once the DOM is ready

  });

The text and image plugins allow require.js to load text and image files.

  define([

    'text!review.txt',

    'image!cat.jpg'

    ],

    function(review,cat){

      console.log(review);

      document.body.appendChild(cat);

    }

  );

Similar plugins are json and mdown for loading json files and markdown files.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324690597&siteId=291194637