有了seajs、requireJ这样的模块加载框架,一直想研究,今天先尝试自己来写一下简单的加载功能,等了解后再去看大牛们的源码,仅当作为自己学习练习,有很多考虑不周的地方请指出,主要就两个方法:
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下载地址:点我点我点我
相关推荐
中心思想:通过外部调用事先封装好的模块加载方法,传入参数(包括主目录及模块js或者css的目录 ),在程序运行的同时,会动态的将相应的css或者是js代码追加引用到head标签内,这样,就可以使用被引用的文件的样式...
KittyJS 是一个超轻量级但完整的 AMD 兼容模块加载器,具有: 支持加载器插件; 支持 Common Config,包括 BaseUrl、paths、packages、map、config 和 shim。 它最初被命名为“SimpleAndNaiveJS”,因为它的实现...
RoboJS是一个库,旨在根据DOM的构成动态加载JS模块。 向DOM添加一个节点,将加载JS! 删除节点,JS将被处置!! 不再是框架前端,而是一个工具,您可以在少于4k的压缩时间内管理DOM和JS关联; 代码背后的想法 要了解...
加载程序 一个小型图书馆,可帮助您在使用流行JavaScript框架和捆绑程序构建的应用程序中使用 。...从ArcGIS API for JavaScript加载模块从最新版本这是一个示例,说明如何加载和使用最新的4.x版本中的WebMap和
****模块(并行)加载器和备用依赖项解析器**** 独立; 没有javascript框架依赖性。 在模块级别解决模块依赖性。 将domReady检查移至模块级别,因此您无需在实现时对其进行编码。 允许预加载模块。 ****目标***...
团块运行时模块捆绑,请求批处理,预期的依赖项加载以及localStorage缓存可消除对JavaScript资产的多余HTTP请求。 通过注入requirejs并劫持其HTTP加载功能,它可以在与requirejs兼容的AMD项目中工作。 然后可以对...
这可能会用作浏览器端的主干: 隔离范围模块加载(CommonJS 可以在此基础上实现)。 客户端 HTML 模板,可以访问某些定义的变量。 定义自定义 JavaScript 环境 (API),然后加载与自定义 API 交互的外部脚本文件(将...
最近要涉及微信移动端项目,所以尝试学习一些移动端的实用技能,这个demo服务由Node搭建服务、下拉加载使用插件dropload,数据渲染应用了ES6中的模板字符串。有兴趣的小伙伴可以自己尝试下。 1.Node+express — 服务...
如果需要,下载模块颜色,并使用当前范围内加载的颜色启动nodejs REPL,以供您使用。 trymodule colors lodash 与上述相同,但一次性包含许多包装! trymodule colors=c lodash=l 将包分配给自定义变量名称。 ...
苦力——一个纯净、易用的模块加载器。 require('some.js'); require('some.css', 'css'); require('some.html', 'html'); require('some.png', 'image'); require('some.json', 'json'); coolie book: 构建工具: ...
一键,离线,CommonJS... script type =" text/javascript " src =" ./one-click.js " data-main =" ./my-module.js " > 它遵循节点解析,因此: require('something/foo.js') 将在node_modules/foo.js搜索。 和
koa-load-routes 中间件使用模块从文件和目录加载路由 警告 要使用此模块,需要Node.js 8.0和或最新版本。 由于v2.0 koa-load-routes不再支持... 模块将尝试从中加载路由的路径(如果是文件),它将读取文件内部定义
(您也可以将konami.js用作具有任何兼容加载程序(例如RequireJS)的AMD模块,在这种情况下,应将模块引用本身用作构造函数,而不是下面的示例中的全局“ Konami”对象。) 在您的代码中,创建一个新的Konami对象...
require.js将尝试加载它 almond.js将失败 但是esquire.js将等待。 例子 在这里,我们有依赖于jquery的应用程序模块。 但是jQuery尚不可用。 它将在以后的某个地方定义。 < script type =" text/javascript " &...
使用Browserify进行异步模块加载的简介: 安装 npm install externalize 原料药 模块导出单个功能 externalize( , , ); 例子 创建两个捆绑,其中第二个捆绑是父捆绑的子集,并在其上调用externalize(parent, ...
问题:小沙盘->window.parent地图存在bug,可以尝试开启 2009-10-23 1.在小沙盘中增加浮动绿色框 2009-11-6 1.实现“鹰眼地图”不需移动,一幅可以看到见全景, 当主场景移动时,“鹰眼地图”只有小框在移动。 ...
使用的模块 表示 https ws 用法 node app.js [secure] 如果指定了可选的secure参数,则服务器将使用配置为localhost的自签名证书进行侦听。 证书是使用以下方法创建的: openssl req -x509 -newkey rsa:2048 -...
为什么要使用CrossJS样式指南? 采用CrossJS风格意味着您的javascript可以在任何环境中工作而...一幅大图像的加载速度比js更快。 我还建议您尝试并执行性能测试。 如果您遵循此规则,则可能只用很少一部分就可以编写
除了处理命名空间之外,它不会做任何事情:例如,它不会尝试加载其他脚本或模块。 它遵循我的一些设计标准: 我希望每个文件都有一个 IIFE 风格的闭包。 这样我就可以有一个"use strict"; 每个文件中的语句,而不会...
// true在浏览器中使用模块加载器(AMD或commonjs)或直接通过全局IBAN对象: < script src =" iban.js " > </ script >< script > // the API is now accessible from the window