你的位置:首页 > Java教程

[Java教程]javascript 异步模块加载 简易实现

  在javascript是没有类似java或其他语言的模块概念的,因此也不可能通过import或using等关键字来引用模块,这样造成了复杂项目中前端代码混乱,变量互相影响等。

  因此在复杂项目中引入AMD的概念,AMD:全称是Asynchronous Module Definition,即异步模块加载机制。通过AMD可以不需要在页面中手动添加<script>来引用脚本,而通过定义依赖自动加载模块脚本,接下来的代码将讲解如何实现建议的AMD模块,如果需要查看比较详细的实现可以下载requirejs源码。

简易实现整体思路:

 

1.将模块名及模块文件地址存入内存

2.通过define方法将模块名及模块依赖关系以及模块实现代码存入内存

3.require方法通过loadscript方法将需要依赖的模块代码导入并执行define方法存入内存,模块通过入参传入实际代码中,从而完成模块加载。

 

1.定义模块:

实现模块的定义,并将模块定义存储。

      /**      *      * @param id 模块名       * @param deps 依赖模块       * @param factory 模块实现       */      define: function (id, deps, factory) {

 

在定义模块中,需要将模块名,模块依赖,模块代码存储至内存中

      /**      *      * @param id 模块名       * @param deps 依赖模块       * @param factory 模块实现       */      define: function (id, deps, factory) {        // 模块是否存在        if (modules[id]) throw new Error("module:" + id + "已经存在!");        if (arguments.length > 2) {          modules[id] = {            id: id,            deps: deps,            factory: factory          }        }        else if (arguments.length == 2) {          modules[id] = {            id: id,            factory: deps          }        }        else {          throw new Error("module:参数有误!");        }      },

2.引用模块:

输入依赖模块名,执行代码,代码示例如下:

      /**      * 异步导入模块       * @param deps 依赖模块       * @param callback      * @returns {{}}      */      require: function (deps, callback) {        // 插入脚本        deps = [].slice.call(deps);        // 获取依赖脚本        loadScript(deps, buildModule, callback);      },

详细步骤:

首先需要从依赖的文件夹中导入脚本,

    /**    * 从外部加载js    * @param deps 依赖模块     * @param buildModule 创建模块方法     * @param callback    */    function loadScript(deps, buildModule, callback) {      var depJsCounter = 0;      deps.forEach(function (dep) {        var script = document.createElement("script")        script.type = "text/javascript";        script.src = configs[dep];        document.getElementsByTagName("head")[0].appendChild(script);        script.onload = function () {          // 依赖js加载计数标记          depJsCounter++;          if (depJsCounter == deps.length) {            buildModule(deps, callback)();          }        };      });    }

构建模块,从全局module中取出依赖模块,将依赖模块作为入参注入到现有模块,最后执行现有模块

    /**     * 创建模块     * @param deps 依赖模块     * @param callback     * @returns {Function}     */    var buildModule = function (deps, callback) {      return function () {        // 获取依赖模块        var args = [];        deps = [].slice.call(deps);        deps.forEach(function (dep) {          var module = modules[dep]          if (typeof module.factory === 'function')            module.factory = module.factory();          args.push(module.factory)        })        // 将依赖模块注入到callback中        var temp = {};        callback.apply(temp, args);        return temp      }    }

3.注册模块

注册模块主要将名字与文件路径关联起来,便于从路径中下载js,代码清单如下:

      /**       * 注册模块       * @param obj       */      config: function (obj) {        var path = obj.paths;        for (var el in path) {          Object.defineProperty(configs, el, {            enumerable: false,            configurable: false,            writable: true,            value: path[el]          })        }      }    }

 

4.执行实例

编写模块

define('module1', function () {  var module1 = {};  module1.sayhello = function () {    return 'hello module1';  }  return module1;});

将代码保存js文件并取名module1

新建html文件,在html中先注册模块,通过require 导入模块,并利用模块编写代码

<!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8">  <title></title>  <script src="http://www.cnblogs.com//demo/01Requirejs/require.js"></script></head><body></body></html><script>require.config({  paths:{    module1:'/demo/01Requirejs/module1.js'  }});require(['module1'],function(module1){  alert(module1.sayhello());})</script>