JS模块加载系统设计V1

一、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下面也会介绍

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏IT笔记

如何限制input输入类型

1.只能输入和粘贴汉字 <input onkeyup="value=value.replace(/1/g,'')" onbeforepaste="clipbo...

3997
来自专栏程序员互动联盟

android apk 防止反编译技术第二篇-运行时修改字节码

上一篇我们讲了apk防止反编译技术中的加壳技术,如果有不明白的可以查看我的上一篇博客http://my.oschina.net/u/2323218/blog/3...

40511
来自专栏好好学java的技术栈

java基础提升篇:深入浅出Java多线程

1272
来自专栏写代码的海盗

scala actor编程之对象传递

scala 最吸引人的一点就是actor并发编程了。但是纵观scala官方文档,baidu文档,IBM文档都写的通过字符串传呀传,如果用作actor编程说明当然...

2919
来自专栏Java架构沉思录

你真的懂volatile关键字吗

volatile这个关键字可能很多朋友都听说过,或许也都用过。在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结...

1211
来自专栏爱撒谎的男孩

struts核心配置文件详解(package)

3386
来自专栏Python爬虫实战

Python指南:文件处理

哪种文件格式最适合用于存储整个数据集——二进制、文本还是XML?这严重依赖于具体的上下文。

1461
来自专栏Java编程技术

一个有关定时生产与消费的问题

按照上面的逻辑看的话,每个队列里面最多有一个元素。其实不然,因为在多线程模型中每个线程占用cpu执行的时间是按照时间片来划分的,每个线程执行完自己的时间片后会被...

821
来自专栏Java 源码分析

synchronized 原理分析

synchronized 原理分析 1. 在阅读源码时做了大量的注释,并且做了一些测试分析源码内的执行流程,由于博客篇幅有限,并且代码阅读起来没有 IDE 方...

2563
来自专栏微信公众号:Java团长

Java网络爬虫基础知识

Java 网络爬虫具有很好的扩展性可伸缩性,其是目前搜索引擎开发的重要组成部分。例如,著名的网络爬虫工具 Nutch 便是采用 Java 开发,该工具以 Apa...

1572

扫码关注云+社区

领取腾讯云代金券