• 关于js模块加载的尝试


    关于js模块加载的尝试

    看了sea.js、requireJs那么完善的模块加载框架,今天尝试来自己写一下简单的加载功能,仅当作为自己学习练习,有很多考虑不周的地方请指出,主要就两个方法:

    VM.define(‘模块名称’,{url:‘模块路径’,requires:‘模块依赖项’(可以是模块名的字符串,或者数组)});  

    VM.use(‘模块名称’,‘回调函数callback’);

    一个是定义模块,一个是使用模块;使用的模块都必须先定义,

    定义的时候不会加载模块,只有在使用的时候才加载模块;

    1、不会出现重复加载的模块,调用过的模块不会再append第二次,不能定义相同名字的模块;

    2、依赖项可以是多个,从左到右加载,多个的时候用数组传参,单个时可以用字符串传参;

    3、支持链式调用,要避免循环依赖的情况;

    修改:上次的代码存在考虑不周的情况,多谢园友 程序猿小卡 留言的指出,现再的也可能有问题,但是如果正常使用依赖,相信还是能够满足的,仅供研究:)

    代码如下:使用方法:只需引入myModule.js文件, <script type="text/javascript" src="myModule.js"></script>

    myModule.js代码如下:

    复制代码
      1 /**
      2 
      3  * Author : vvg
      4 
      5  * version : 0.1.1
      6 
      7  * name : VModule.js
      8 
      9  **/
     10 
     11 (function () {
     12     // 调试提示
     13     var log = function (content) {
     14         if (typeof console.log === 'function') {
     15             console.log(content);
     16         } else {
     17             alert(content);
     18         }
     19     }
     20 
     21     var createScript = function (url) {
     22         var script = document.createElement('script');
     23         script.type = 'text/javascript';
     24         script.src = url;
     25         return script;
     26     };
     27 
     28     var head = document.getElementsByTagName('head')[0];
     29     var toString = Object.prototype.toString;
     30 
     31     var VModule = {};
     32     /**
     33      * 定义模块
     34      * @param name  {string}
     35      * @param options {object}  url/requires
     36      */
     37     VModule.define = function (name, options) {
     38         //定义模块名称、地址和依赖
     39         if (!this.modules) this.modules = {};
     40         if (this.modules[name]) {
     41             log(name + '已经存在,请更换名称.');
     42             return;
     43         }
     44         this.modules[name] = options;
     45         // 是否加载
     46         this.modules[name].isLoad = false;
     47         // 是否使用
     48         this.modules[name].isUse = false;
     49         // 回调队列
     50         this.modules[name].callBackQueue = [];
     51         return this;
     52     }
     53 
     54     VModule.use = function (name, func) {
     55         var len, self = this;
     56         if (!this.modules[name]) {
     57             log(name + '不存在.');
     58             return this;
     59         }
     60         // 回调队列,用于多次use同一个模块时的多个回调
     61         var callBackQueue = this.modules[name].callBackQueue;
     62         if (!this.modules[name].isUse) {
     63             // 标记模块已经使用过
     64             this.modules[name].isUse = true;
     65             // 推入队列
     66             callBackQueue.push(func);
     67             var url = this.modules[name].url;
     68             var requires = this.modules[name].requires;
     69 
     70             // 串行依赖情况
     71             if (toString.call(requires) == '[object String]') {
     72                 this.use(requires, function () {
     73                     self.load(name, callBackQueue);
     74                 });
     75                 return this;
     76             }
     77 
     78             // 并行依赖处理
     79             if (toString.call(requires) == '[object Array]') {
     80                 //循环查找
     81                 len = requires.length;
     82                 this.modules[name].count = len;
     83                 for (var i = 0; i < len; i++) {
     84                     var self = this;
     85                     this.use(requires[i], function () {
     86                         VModule.modules[name].count--;
     87                         // 串行依赖即等待所有的文件加载完毕后才执行回调
     88                         if (VModule.modules[name].count == 0) {
     89                             self.load(name,callBackQueue);
     90                         }
     91                     })
     92                 }
     93                 return this;
     94             }
     95             this.load(name, callBackQueue);
     96         } else {
     97             // 如果模块已经标记使用,但是模块还未下载完毕时,加入队列, 如果下载完毕则直接执行回调函数
     98             if(!this.modules[name].isLoad){
     99                 func && callBackQueue.push(func);
    100             }else{
    101                 func && func();
    102             }
    103             return this;
    104         }
    105     }
    106     VModule.load = function (name, callBackQueue) {
    107         if (!this.modules[name].isLoad) {
    108             var self = this;
    109             var script = createScript(self.modules[name].url);
    110             script.onload = script.onreadystatechange = function () {
    111                 if ((!this.readyState) || this.readyState === "loaded" || this.readyState === "complete") {
    112                     self.modules[name].isLoad = true;
    113                     // 循环调用回调队列
    114                     for(var i = 0, n = callBackQueue.length;i<n;i++){
    115                         callBackQueue[i]();
    116                     }
    117                 }
    118             }
    119             head.appendChild(script);
    120         }
    121     }
    122 
    123     window.VM = VModule;
    124 
    125 })();
    复制代码

    我的测试DEMO:

    复制代码
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8"/>
        <title>js模块化</title>
        <script type="text/javascript" src="Module.js"></script>
    </head>
    <body>
    <p id="jq">测试</p>
    
    <p id="jq2">测试</p>
    <script type="text/javascript">
        VM.define('a', {url:'moduleA.js', requires:['b', 'd', 'c']})
                .define('b', {url:'moduleB.js'})
                .define('c', {url:'http://common.cnblogs.com/script/jquery.js?178979879891'})
                .define('d', {url:'moduleD.js', requires:['e', 'g', 'f']})
                .define('e', {url:'moduleE.js', requires:'f'})
                .define('f', {url:'moduleF.js'}).define('g', {url:'moduleG.js'});
        VM.use('a', function () {
            $('#jq').html('JQ下载成功!!').css('color', 'red');
        }).use('a', function () {
                    $('#jq2').html('JQ下载成功!!').css('color', 'red');
        }).use('a',function(){
                    $('#jq2').append('<em>第三次加载</em>').find('em').css('color','blue');
        }).use('f',function(){
                    console.log('F加载成功!');
                })
    
    </script>
    </body>
    </html>
    复制代码

     DEMO下载地址:点我点我点我

    转载请注明出处:http://www.cnblogs.com/NNUF/

     
    分类: JS实例原创
  • 相关阅读:
    5.单表查询
    3.数据类型1
    3.数据类型2
    mysql用户操作和权限管理
    【剑指Offer】面试题27. 二叉树的镜像
    【LeetCode】160. 相交链表
    【剑指Offer】面试题52. 两个链表的第一个公共节点
    【LeetCode】206. 反转链表
    【剑指Offer】面试题24. 反转链表
    LeetCode题解分类汇总(包括剑指Offer和程序员面试金典,持续更新)
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2942087.html
Copyright © 2020-2023  润新知