前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JS模块加载系统设计V1

JS模块加载系统设计V1

作者头像
郑小超.
发布2018-01-24 16:21:16
6970
发布2018-01-24 16:21:16
举报
文章被收录于专栏:GreenLeavesGreenLeavesGreenLeaves

一、require模块

    +function() {
        var path = location.protocol + "//" + location.host +"/Javasript框架设计/common/";
        require.config({
            alias: {
                "jquery": {
                    src: path + "mass/demo/jquery-1.9.1.min.js",
                    deps: [],//没有依赖可以不写
                    exports: "jQuery" //要从全局作用域抽取的数据
                }
            }
        });
        require("jquery", function($) {
            alert($)
            alert($("body").length);
            alert("回调调起成功");
            alert($("body").length) //这里不用domReady了
        })
    }()

以上是源码

我喜欢以剖析源代码的方式去学一种技术,上面这段代码是标准的requireJs的语句,但是这是mass.js版本的requireJs,下面就来解读源代码:

var path = location.protocol + "//" + location.host +"/Javasript框架设计/common/"

这个path是网站的根路径,方便mass寻找Js和css的文件.

  require.config({
            alias: {
                "jquery": {
                    src: path + "mass/demo/jquery-1.9.1.min.js",
                    deps: [],//没有依赖可以不写
                    exports: "jQuery" //要从全局作用域抽取的数据
                }
            }
        });

这段代码主要是记载系统的文件别名机制,通过给想要加载的文件起一个别名,并且指定该文件的路径。下面来看mass是如何实现这个功能的:

    (function() {
        var cur = getCurrentScript(true);
        if (!cur) {//处理window safari的Error没有stack的问题
            cur = $.slice(document.scripts).pop().src;
        }
        var url = cur.replace(/[?#].*/, "");
        kernel = $.config;
        kernel.plugin = {};
        kernel.alias = {};
        basepath = kernel.base = url.slice(0, url.lastIndexOf("/") + 1);
        var scripts = DOC.getElementsByTagName("script");
        for (var i = 0, el; el = scripts[i++]; ) {
            if (el.src === cur) {
                kernel.nick = el.getAttribute("nick") || "$";
                break;
            }
        }
        kernel.level = 9;
    })();

通过这个自执行函数,将$.config函数对象托管给kernel对象

require.config = kernel;

然后在将kernel对象托管给require.config对象,require.config其实就是$.config函数对象,也就是说你通过require.config传递的参数,实际都会传递给$.config函数,个人觉得这个设计蛮不错的,当我们以后有新的模块需要进行类似的配置时,也可以通过这种方式,增强了代码的复用性。

再来看$.config做了什么?

  config: function(settings) {
            for (var p in settings) {
                if (!hasOwn.call(settings, p))
                    continue;
                var val = settings[p];
                if (typeof kernel.plugin[p] === "function") {
                    kernel.plugin[p](val);
                } else {
                    kernel[p] = val;
                }
            }
            return this;
        }
  require.config({
            alias: {
                "jquery": {
                    src: path + "mass/demo/jquery-1.9.1.min.js",
                    deps: [],//没有依赖可以不写
                    exports: "jQuery" //要从全局作用域抽取的数据
                }
            }
        });

源码传递给config一个属性名为alias的对象集合,然后通过config遍历这个集合,过滤其中的属性(不是该对象的原生属性(也就是通过原型链添加的属性)),然后判断当前遍历到的属性是否是kernel对象的插件(这里用函数表示),如果是吊用该插件,然后通过当前的属性,拿到对应对象的值,将值作为参数传递给该插件。

这里的alias是kernel的一个插件,下面是他的源码:

    kernel.plugin["alias"] = function(val) {
        var map = kernel.alias;
        for (var c in val) {
            if (hasOwn.call(val, c)) {
                var prevValue = map[c];
                var currValue = val[c];
                if (prevValue) {
                    $.error("注意" + c + "出经重写过");
                }
                map[c] = currValue;
            }
        }
    };

这个函数也就是上面所说的alias插件,该函数通过维护一个alias集合来保存所有需要加载的文件的别名和对应的js路径

1、首先拿到所有的alias(别名),这里注意:

var all = "mass,lang,class,flow,data,support,query,node,attr,css,event,ajax,fx";

mass事先把属于自身框架的所有js文件都放到了这个集合当中去了。

2、遍历传入的参数,做一些常规判断,如果命名相同,则进行重写操作,并进行提醒,不相同直接加入到alias集合中去

加下来看require方法了:

   require("jquery", function($) {
            alert($)
            alert($("body").length);
            alert("回调调起成功");
            alert($("body").length) //这里不用domReady了
        })

上面的代码传递给reqiire方法一个"jquery"和一个回调函数参数,下面来分析require方法的源码:

    window.require = $.require = function(list, factory, parent) {
        // 用于检测它的依赖是否都为2
        var deps = {},
                // 用于保存依赖模块的返回值
                args = [],
                // 需要安装的模块数
                dn = 0,
                // 已安装完的模块数
                cn = 0,
                id = parent || "callback" + setTimeout("1");
        parent = parent || basepath;
        String(list).replace($.rword, function(el) {
            var url = loadJSCSS(el, parent)
            if (url) {
                dn++;
                if (modules[url] && modules[url].state === 2) {
                    cn++;
                }
                if (!deps[url]) {
                    args.push(url);
                    deps[url] = "司徒正美"; //去重
                }
            }
        });
        modules[id] = {//创建一个对象,记录模块的加载情况与其他信息
            id: id,
            factory: factory,
            deps: deps,
            args: args,
            state: 1
        };
        if (dn === cn) { //如果需要安装的等于已安装好的
            fireFactory(id, args, factory); //安装到框架中
        } else {
            //放到检测列队中,等待checkDeps处理
            loadings.unshift(id);
        }
        checkDeps();
    };

1、require方法接收三个参数:

(1)、第一个list,如果通过config配置过别名和路径的话,那么这个list就是别名列表,如果不是的话,LoadJSCSS方法会做进一步的处理,下面会介绍LoadJSCSS方法。

(2)、都二个factory,这个参数是回调函数

(3)、第三个parent,可以通过这个参数指定basePath,basePath下面也会介绍

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-02-27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档