使用requirejs 使用方法怎么进行DOM1.0的事件绑定

用心创造滤镜
扫码下载App
汇聚2000万达人的兴趣社区下载即送20张免费照片冲印
扫码下载App
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
阅读(11305)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_',
blogTitle:'JQuery
DOM事件绑定、移除、只执行一次',
blogAbstract:'
1、DOM事件绑定:bind():可以为同一个元素绑定多个事件,也可以为多个元素绑定同一个事件。
//多个元素绑定同一个事件:
$(\"#btn1,#btn2\").bind(\"click\", function () {&&&&&&&&&&&&&&& $(\"#myTable tr:last\").remove();
&&&&&&&&&&& });
//一个元素绑定多个事件$(\"#btn1\").bind(\"mouseover\", function () {',
blogTag:'',
blogUrl:'blog/static/5',
isPublished:1,
istop:false,
modifyTime:3,
publishTime:6,
permalink:'blog/static/5',
commentCount:0,
mainCommentCount:0,
recommendCount:0,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:true,
hostIntro:'',
hmcon:'0',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}当前访客身份:游客 [
已有文章 2133 篇
当前位置:
使用 RequireJS 实现 JavaScript 的延迟加载
英文原文:
0人收藏此文章,
推荐于 3年前 (共 7 段, 翻译完成于 01-12) ()
参与翻译(2人):
无论简单还是复杂的Web应用,都由一些HTML、JavaScript、CSS文件组成。通常开发者会通过JQuery、Knockout、Underscore等等这样的第三方JavaScript框架来提高开发速度。由于这些JavaScript框架都针对特定的用途开发而且已经得到了“验证”,所以直接使用它们就比自己从头实现所需要的功能显得更为合适。然而,伴随着应用的复杂度不断上升,写出干净、低耦合、可维护的代码变得越来越重要。在这篇文章里,我将解释
框架如何帮助应用开发者写出更加模块化的代码,以及它是如何通过延迟加载JavaScript文件来提高应用性能的。
&翻译的不错哦!
开始的部分我们先不用RequireJS框架,然后在下一个章节用RequireJS来重构它。
下面的这个HTML页面包含了一个id为“message”的&p&元素。当用户访问这个页面的时候,它将展示订单Id和客户姓名信息。
Common.JS文件包含了两个模块的定义——Order和Customer。函数showData和页面的body结合在一起,它通过调用write函数来把要输出的信息放入页面中。作为示例,我在showData函数里硬编码了Id为1,客户姓名为Prasad。
&!DOCTYPE html&
&title&JavaScript NonRequireJS&/title&
&script src="common.js" type="text/javascript"&&/script&
&strong&Display data without RequireJS&/strong&
&p id="message" /&
&script type="text/javascript"&
showData();
function write(message) {
document.getElementById('message').innerHTML += message + '&/br&';
function showData() {
var o = new Order(1, "Prasad");
write("Order Id : " + o.id + " Customer Name : " + o.customer.name);
function Customer(name) {
this.name =
function Order(id, customerName) {
this.customer = new Customer(customerName);
在浏览器中打开这个页面,你将看到如下的信息。
&翻译的不错哦!
虽然上面的代码能够显示输出,但是它仍有一些问题:
Common.JS文件包含了所有需要定义的函数(write,showData),而且模块(Order,Customer)很难维护和复用。假如你想在其它页面里复用write函数并引用了上面的JavaScript文件,那么你也导入了这个页面可能不需要的其它函数和模块。
Order模块(或者在面向对象中叫做“类”)在初始化过程中创建了一个Customer模块的实例。这意味着Order模块依赖于Customer模块。这些模块间的紧耦合使得将来在优化时很难重构与维护。
每当客户端请求这个页面时,Common.JS文件就会被载入DOM。在上面这个例子中,尽管我们只需要在页面上输出信息,但我们仍把那些不需要的模块(Customer,Order)载入了内存。载入不必要的应用资源(JavaScript、CSS、图片文件等等)会降低应用的性能。
Common.JS文件里的模块可以被分离到不同的JavaScript文件里,但是当应用变得越来越复杂时,很难判断JavaScript文件之间的依赖关系与需要被加载的文件的加载顺序。
RequireJS框架处理了JavaScript文件间的依赖关系,并且根据需要按顺序加载它们。
&翻译的不错哦!
用RequireJS搭建应用
现在让我们看看重构过的代码。下面的HTML代码引用了Require.JS文件。data-main属性定义了这个页面的唯一入口点。在下面这个场景中,它告诉了RequireJS在启动的时候加载Main.js。
&!DOCTYPE html&
&title&JavaScript RequireJS&/title&
&script src="Require.Js" type="text/javascript" data-main="Main.js"&&/script&
&strong&Display data using RequireJS&/strong&
&p id="message" /&
&翻译的不错哦!
由于这个文件已经通过data-main属性指定,RequireJS将会尽快的加载它。这个文件使用了RequireJS框架的函数来确定和定义对于其它JavaScript文件的依赖关系。在下面的代码片段里,第一个参数表示依赖关系(依赖Order.JS文件),第二个参数为一个回调函数。RequireJS分析所有的依赖关系并载入它们,然后执行这个回调函数。请注意,第一个参数的值(Order)必须和文件名一致(Order.JS)。
require(["Order"], function (Order) {
var o = new Order(1, "Prasad");
write(o.id + o.customer.name);
&翻译的不错哦!
RequireJS框架提供了一个定义和维护JavaScript文件间依赖关系的简便途径。下面代码中的define函数声明了Customer.JS必须在处理Order回调函数前载入。
define(["Customer"],
function (Customer) {
function Order(id, custName) {
this.customer = new Customer(custName);
Customer.JS
这个文件不依赖于任何其它JavaScript文件,所以define函数的第一个参数的值是一个空数组。
define([],
function () {
function Customer(name) {
this.name =
&翻译的不错哦!
好了,现在用你的浏览器打开这个应用,你将会看到如下的输出。要注意的是RequireJS只载入了必需的JavaScript文件。
在这篇文章里,我们分析了RequireJS框架是如何处理JavaScript文件间的依赖关系并根据需要载入它们的。它能够帮助开发者写出更松耦合、更模块化且更具有可维护性的代码。
下载源代码:
&翻译的不错哦!| 时间排序
AMD 是一家芯片公司&br&CMD 是命令行程序
AMD 是一家芯片公司CMD 是命令行程序
用requirejs遇到问题可以google,用seajs你就慢慢百度吧。
用requirejs遇到问题可以google,用seajs你就慢慢百度吧。
异步加载和异步执行是两个概念&br&&br&script标签是会阻塞页面的 是同步的 下载的时候不会进行任何操作的 加了defer或async就可以同时下载和渲染之类的操作。变成了异步下载。&br&异步是指下载的异步。&br&是同时一定数量的js文件下载 然后执行 具体自己查吧。&br&&br&模块化最重要的还是让下一个开发的人舒服。降低耦合,依赖清晰,调bug加需求都比较容易。&br&坏处是需要全部加载完才能执行。&br&异步是指执行上的异步。是指被依赖的模块执行完了,才去执行要执行的模块。require seajs 都是需要把内容加载完解析依赖以后再执行&br&&br&&br&异步是前端的必需属性啊。网络延迟大的情况还有很多函数是异步。seajs是模仿commonjs的加载机制 原始的概念是不主张异步加载的 主张的是依赖就进,按需加载。但做不到真正的按需加载,就慢慢被淘汰了。
异步加载和异步执行是两个概念script标签是会阻塞页面的 是同步的 下载的时候不会进行任何操作的 加了defer或async就可以同时下载和渲染之类的操作。变成了异步下载。异步是指下载的异步。是同时一定数量的js文件下载 然后执行 具体自己查吧。模块化最重要…
泻药&br&&br&可能的优点:&br&&ol&&li&公用模块被加载一次以后缓存在本地,再次加载时更快速,且可以多页面共享这个福利。公用度越高的模块,福利越大&br&&/li&&li&更新功能或者修bug,只需要更新部分模块,其它未变化模块缓存在本地福利不变,更新后用户下载文件量相对小&/li&&li&可控制加载机制,让一部分非主要的内容(如首屏外内容等),等到使用时再载入&/li&&li&全局公用模块可独立上线(在保证兼容等问题的情况下),不用全线产品都跟着重新打包上线&/li&&/ol&可能的缺点:&br&&ol&&li&过多的文件导致浏览器HTTP线程用尽,其他资源文件被迫等&/li&&li&网络不好时,过多文件加载导致链路拥堵更严重&/li&&li&碎文件的CDN同步文件时间是否同步问题&/li&&li&过多小文件导致实际总connect 时间比数据总 download 时间还长,造成可能的时间浪费&/li&&/ol&都合并呢,基本上是这个优缺点的相反&br&所以实际中&br&更可能是混合使用&br&&br&不过&br&我认为&br&SeaJS, Require.js 这些&br&作为模块化开发的通用规范意义更大点&br&跟否是有加载(前端优化)效率没太大关系&br&它的这些效率上优点几乎都是&br&该种模块管理方式的附属品而已&br&而该种模块管理方式&br&是基于浏览器就不能同步加载JS的实际情况&br&作出的妥协实现方式
泻药可能的优点:公用模块被加载一次以后缓存在本地,再次加载时更快速,且可以多页面共享这个福利。公用度越高的模块,福利越大更新功能或者修bug,只需要更新部分模块,其它未变化模块缓存在本地福利不变,更新后用户下载文件量相对小可控制加载机制,让…
分享一个我的前后端分离的开源项目,&br&纯属个人学习项目,&br&大学如果喜欢的话,&br&就尽管使用吧,&br&方便的话可以加个star,&br&然后pull request,&br&哈哈,&br&个人使用到现在还没有遇到什么问题,&br&&a href=&/az8321550/express-velocity-front-end& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&az8321550/express-velocity-front-end · GitHub&i class=&icon-external&&&/i&&/a&&br&&br&谢谢大家多多支持!
分享一个我的前后端分离的开源项目,纯属个人学习项目,大学如果喜欢的话,就尽管使用吧,方便的话可以加个star,然后pull request,哈哈,个人使用到现在还没有遇到什么问题,谢谢大家多多支持!
谢谢你的回答!我还是有疑问,如果在捕获列表里没有出现index.js是无法代理的?&br&我今天第一次用手机代理,访问测试地址,确实补捕获目标路径。&br&如图1:&img src=&/a55a5daacf_b.jpg& data-rawwidth=&660& data-rawheight=&75& class=&origin_image zh-lightbox-thumb& width=&660& data-original=&/a55a5daacf_r.jpg&&此时,我希望接下去通过本地代理文件的方式替换这个路径。&br&&img src=&/f02c67acd15643cac06aff_b.jpg& data-rawwidth=&605& data-rawheight=&153& class=&origin_image zh-lightbox-thumb& width=&605& data-original=&/f02c67acd15643cac06aff_r.jpg&&但是,当我第二次访问测试地址时,左边的捕获列表中没有出现图1中的地址,怎么回事呢?这也导致我无法替换这个路径。&br&&img src=&/045f5d3de57b3b0d281b04e8df1ecabe_b.jpg& data-rawwidth=&668& data-rawheight=&68& class=&origin_image zh-lightbox-thumb& width=&668& data-original=&/045f5d3de57b3b0d281b04e8df1ecabe_r.jpg&&
谢谢你的回答!我还是有疑问,如果在捕获列表里没有出现index.js是无法代理的?我今天第一次用手机代理,访问测试地址,确实补捕获目标路径。如图1:此时,我希望接下去通过本地代理文件的方式替换这个路径。但是,当我第二次访问测试地址时,左边的捕获列…
就是随便模块化的问题,JS没有模块化机制,只能自己搞了。&br&&br&至于“异步”,那不过是因为JS不异步没法做事了。
就是随便模块化的问题,JS没有模块化机制,只能自己搞了。至于“异步”,那不过是因为JS不异步没法做事了。
使用异步加载是需要两个前提的:&br&&ol&&li&为了将代码复用使浏览器可以缓存,并处理命名空间产生的问题,将代码分为模块&br&&/li&&li&为了遵循模块间的依赖关系,模块必须按顺序加载&br&&/li&&/ol&&br&由此产生了三个问题:&br&&ol&&li&当模块依赖关系很复杂时,排序就成了一件难题&br&&/li&&li&按顺序下载大量JS文件时会导致页面暂时失去响应&br&&/li&&li&无法实现按需加载模块,例如当浏览器支持某一特性时,加载A,否则加载B&br&&/li&&/ol&&br&R和C解决以上3个问题。
使用异步加载是需要两个前提的:为了将代码复用使浏览器可以缓存,并处理命名空间产生的问题,将代码分为模块为了遵循模块间的依赖关系,模块必须按顺序加载由此产生了三个问题:当模块依赖关系很复杂时,排序就成了一件难题按顺序下载大量JS文件时会导致页…
&a href=&/blog/pc-spa-js-build/& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&/blog/pc-s&/span&&span class=&invisible&&pa-js-build/&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&
占坑。&br&&br&对我来说,未来的最佳方案还是loader而不是bundling。原因简单说就是bundling优化很容易就达到上限,更精细的优化在工程上几乎是不可行的。而browser runtime loader理论上不受此种限制。&br&&br&不过当初require.js或seajs并不是这个出发点。且这些传统loader在工程实践上采用我说的这种优化几乎是空白的。&br&&br&这个问题我跟业界一些同志探讨过,大家多少都认可这一前景,不过暂时还没有付诸实践。所以先这样了,等明年有实践了,再回来填坑吧。
占坑。对我来说,未来的最佳方案还是loader而不是bundling。原因简单说就是bundling优化很容易就达到上限,更精细的优化在工程上几乎是不可行的。而browser runtime loader理论上不受此种限制。不过当初require.js或seajs并不是这个出发点。且这些传统loade…
首先通过下图大体了解下Fiddler等代理工具的工作原理:&br&&img src=&/c3ed7c6b64e806f710c6a17e1e279972_b.png& data-rawwidth=&750& data-rawheight=&405& class=&origin_image zh-lightbox-thumb& width=&750& data-original=&/c3ed7c6b64e806f710c6a17e1e279972_r.png&&&br&然后,列几个代理工作常识:&br&&ol&&li&原始请求由浏览器发出(RequireJS的依赖模块也是如此)&br&&/li&&li&代理是截获了原始请求,重新模拟请求发送给Web Server&br&&/li&&li&代理截获请求可以将请求头和内容修改&br&&/li&&li&代理拿到Web Server的响应后也可以对响应头和内容进行修改&br&&/li&&li&最后响应浏览器的是代理&/li&&/ol&&br&下面开始分析题主的意图:&br&1. 假设main.js包含子模块index,如果题主想在浏览器请求main.js时想知道它包含哪些子模块,那就在上图⑦中可以拿到main.js的内容,然后通过解析AMD规范可以拿到main.js依赖的子模块(解析方法可以用正则表达式,也可以通过js parser拿到AST然后遍历require方法的第一个参数,常用的js parser有&a href=&http://esprima.org/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Esprima&i class=&icon-external&&&/i&&/a& 或 &a href=&/army8735/homunculus& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&army8735/homunculus · GitHub&i class=&icon-external&&&/i&&/a&)&br&2. 如果题主是真正想“捕获子模块”,其实更简单了,因为子模块的请求也是浏览器发出来的,其实过程是:浏览器请求main.js =& 浏览器执行main.js =& 执行到require方法时发送子模块请求。所以题主可以在浏览器发送子模块请求时在上图第②步可以获取请求头得到子模块的路径如:/index.js,这时就相当于捕获了子模块。&br&&br&以上。
首先通过下图大体了解下Fiddler等代理工具的工作原理:然后,列几个代理工作常识:原始请求由浏览器发出(RequireJS的依赖模块也是如此)代理是截获了原始请求,重新模拟请求发送给Web Server代理截获请求可以将请求头和内容修改代理拿到Web Server的响应后…
&blockquote&如果你现有一些以CommonJS模块格式编写的代码,而这些代码难于使用上述依赖名称数组参数的形式来重构,你可以考虑直接将这些依赖对应到一些本地变量中进行使用。你可以使用一个CommonJS的简单包装来实现.&br&&div class=&highlight&&&pre&&code class=&language-text&&define(function(require, exports, module) {
var a = require('a'),
b = require('b');
//Return the module value
return function () {};
&/code&&/pre&&/div&&/blockquote&这个回答了你第一个疑惑。
如果你现有一些以CommonJS模块格式编写的代码,而这些代码难于使用上述依赖名称数组参数的形式来重构,你可以考虑直接将这些依赖对应到一些本地变量中进行使用。你可以使用一个CommonJS的简单包装来实现.define(function(require, exports, module) {
主流的“前端”JS加载器原理都是往DOM里动态插入一个&br&&div class=&highlight&&&pre&&code class=&language-text&&&script src=&X.js&&&/script&
&/code&&/pre&&/div&真正的装载仍然是浏览器自身完成的;模块依赖是加载器自己实现的,因为浏览器无法处理,但最终多模块的装载只是对以上步骤的重复(batch作为一种优化)而已。&br&&br&“主流”的前端JS loader参考&br&&a href=&/javascript/essential-javascript-top-five-script-loaders-8122862& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Essential JavaScript: the top five script loaders&i class=&icon-external&&&/i&&/a&&br&&a href=&/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&StealJS&i class=&icon-external&&&/i&&/a&我个人用得比较多,背后原理相同,但可以在编译时flatten整个依赖树。
主流的“前端”JS加载器原理都是往DOM里动态插入一个&script src="X.js"&&/script&
真正的装载仍然是浏览器自身完成的;模块依赖是加载器自己实现的,因为浏览器无法处理,但最终多模块的装载只是对以上步骤的重复(batch作为一种优化)而已。“主流”的前…
&ul&&li&JS代码的自动检查、清理、整合、压缩&br&&/li&&li&CSS代码的自动检查、编译、压缩&/li&&li&模版的编译、压缩&/li&&li&图片资源的自动压缩,自动Sprite,自动转换&/li&&li&自动test脚手架&/li&&li&以上以及项目日常测试发布所需步骤的流程自动化&/li&&/ul&&a href=&/& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&/&/span&&span class=&invisible&&&/span&&i class=&icon-external&&&/i&&/a&&br&&a href=&/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&gulp.js - the streaming build system&i class=&icon-external&&&/i&&/a&&br&&a href=&https://webpack.github.io/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&webpack module bundler&i class=&icon-external&&&/i&&/a&
JS代码的自动检查、清理、整合、压缩CSS代码的自动检查、编译、压缩模版的编译、压缩图片资源的自动压缩,自动Sprite,自动转换自动test脚手架以上以及项目日常测试发布所需步骤的流程自动化
可以买本司徒正美的&&JavaScript框架设计&&看看,书的第二章详细讲解了js的模块系统原理.
可以买本司徒正美的&&JavaScript框架设计&&看看,书的第二章详细讲解了js的模块系统原理.
&a href=&/yanhaijing/lodjs& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&yanhaijing/lodjs · GitHub&i class=&icon-external&&&/i&&/a& 前段时间写了个AMD加载器,只有500行代码,如果研究源码建议看这个吧,requirejs太复杂了
前段时间写了个AMD加载器,只有500行代码,如果研究源码建议看这个吧,requirejs太复杂了
我来装逼啦,&a href=&/ErosZy/UME.js& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&/ErosZy/UME.j&/span&&span class=&invisible&&s&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a& 两年前写的简单的模块加载。
我来装逼啦, 两年前写的简单的模块加载。
这种简单问题直接看源码,看不懂的说明你还没到达可以理解它原理的水平,说了结果也会被大脑忽略掉,继续学习
这种简单问题直接看源码,看不懂的说明你还没到达可以理解它原理的水平,说了结果也会被大脑忽略掉,继续学习
模块和加载是两个部分&br&模块是说你怎么组织你的代码 针对的是开发者&br&加载是说代码怎么跑到浏览器去 针对的是机器 是运行时&br&&br&一开始这两个部分是合在一起的 也就是所谓的seajs requirejs 优点是按需加载 具体没实现过 不过就是类似于添加script标签加载js文件 同时也要对依赖等问题进行管理&br&&br&后来出现了一些工具如browserify gulp等打包的工具 真正实现了把这个过程分开 首先把代码按照那些模块系统(决定生态环境)打包生成为一个源码包 然后直接通过浏览器原生支持的script link等直接引用就好 这方案的优势在于可以在运行代码前 把代码优化 压缩以及依赖等问题都给解决掉 更适合工程化&br&&br&于是 两种方案各有优劣 所以 我预测下一个解决方案是能把以上组合在一起使用的 那就是es2015 module
模块和加载是两个部分模块是说你怎么组织你的代码 针对的是开发者加载是说代码怎么跑到浏览器去 针对的是机器 是运行时一开始这两个部分是合在一起的 也就是所谓的seajs requirejs 优点是按需加载 具体没实现过 不过就是类似于添加script标签加载js文件 同…
cmd 对于 nodejs 的使用者来说更加友好,使得类似 commonJS 模块的写法可以在浏览器中使用,同时解决了浏览器中模块异步加载的困扰。&br&关于 cmd 更详细的内容可以移步&a href=&/cmdjs/specification/blob/master/draft/module.md& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&specification/module.md at master · cmdjs/specification · GitHub&i class=&icon-external&&&/i&&/a&&br&&br&我们可以通过实现一个简单的 cmd loader,来学习其中的原理和细节。&br&&br&&b&模块加载流程&/b&&br&&br&下图展示了一个 cmd loader 的模块加载大体流程:&br&&img src=&/4e562d8bb1ee9cb467ad0_b.png& data-rawwidth=&654& data-rawheight=&335& class=&origin_image zh-lightbox-thumb& width=&654& data-original=&/4e562d8bb1ee9cb467ad0_r.png&&1. 首先,通过 use 方法来加载入口模块,并接收一个回调函数, 当模块加载完成, 会调用回调函数,并传入对应的模块。use 方法会 check 模块有没有缓存,如果有,则从缓存中获取模块,如果没有,则创建并加载模块。&br&2. 获取到模块后,模块可能还没有 load 完成,所以需要在模块上绑定一个 &complete& 事件,模块加载完成会触发这个事件,这时候才调用回调函数。&br&3. 创建一个模块时,id就是模块的地址,通过创建 script 标签的方式异步加载模块的代码(factory),factory 加载完成后,会 check factory 中有没有 require 别的子模块:&br&
- 如果有,继续加载其子模块,并在子模块上绑定 &complete& 事件,来触发本身 的 &complete& 事件;&br&
- 如果没有则直接触发本身的 &complete& 事件。&br&4. 如果子模块中还有依赖,则会递归这个过程。&br&5. 通过事件由里到外的传递,当所有依赖的模块都 complete 的时候,最外层的入口模块才会触发 &complete& 事件,use 方法中的回调函数才会被调用。&br&&br&&b&功能划分&/b&&br&&br&理解了整个过程,那么我们就来开始实现我们的代码,我们暂且给这个加载器命名为 mcmd 吧。首先是加载器的功能模块划分:&br&&img src=&/141e952d3ecee36dfbf4b_b.jpg& data-rawwidth=&286& data-rawheight=&304& class=&content_image& width=&286&&- mcmd:入口文件,用于定义默认配置,参数,常量等,同时使用或加载其他的功能模块;&br&- define:实现 cmd 中的 &define& 方法;&br&- require:实现 cmd 中的 &require& 方法;&br&- use:实现 cmd 中的 &use& 方法;&br&- module:模块类,实现模块的创建、加载、事件等功能;&br&- load:用于获取模块,把模块从新建和从 cache 中获取封装成统一的接口;&br&- promise:异步任务处理器;&br&- util:工具类函数;&br&&br&&b&构建&/b&&br&&br&我们使用 commonJS 的方式进行编码,并使用 browserify 配合 gulp 来构建我们的项目。&br&&br&&div class=&highlight&&&pre&&code class=&language-js&&
&span class=&kd&&var&/span& &span class=&nx&&gulp&/span& &span class=&o&&=&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'gulp'&/span&&span class=&p&&);&/span&
&span class=&kd&&var&/span& &span class=&nx&&uglify&/span& &span class=&o&&=&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'gulp-uglify'&/span&&span class=&p&&);&/span&
&span class=&kd&&var&/span& &span class=&nx&&concat&/span& &span class=&o&&=&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'gulp-concat'&/span&&span class=&p&&);&/span&
&span class=&kd&&var&/span& &span class=&nx&&browserify&/span& &span class=&o&&=&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'browserify'&/span&&span class=&p&&);&/span&
&span class=&kd&&var&/span& &span class=&nx&&source&/span& &span class=&o&&=&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'vinyl-source-stream'&/span&&span class=&p&&);&/span&
&span class=&kd&&var&/span& &span class=&nx&&buffer&/span& &span class=&o&&=&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'vinyl-buffer'&/span&&span class=&p&&)&/span&
&span class=&kd&&var&/span& &span class=&nx&&pg&/span& &span class=&o&&=&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'./package'&/span&&span class=&p&&);&/span&
&span class=&kd&&var&/span& &span class=&nx&&versionName&/span& &span class=&o&&=&/span& &span class=&nx&&pg&/span&&span class=&p&&.&/span&&span class=&nx&&name&/span& &span class=&o&&+&/span& &span class=&s1&&'.'&/span& &span class=&o&&+&/span& &span class=&nx&&pg&/span&&span class=&p&&.&/span&&span class=&nx&&version&/span&
&span class=&nx&&gulp&/span&&span class=&p&&.&/span&&span class=&nx&&task&/span&&span class=&p&&(&/span&&span class=&s1&&'default'&/span&&span class=&p&&,&/span& &span class=&p&&[&/span&&span class=&s1&&'build'&/span&&span class=&p&&]);&/span&
&span class=&nx&&gulp&/span&&span class=&p&&.&/span&&span class=&nx&&task&/span&&span class=&p&&(&/span&&span class=&s1&&'build'&/span&&span class=&p&&,&/span& &span class=&kd&&function&/span& &span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&nx&&browserify&/span&&span class=&p&&(&/span&&span class=&s1&&'./src/mcmd.js'&/span&&span class=&p&&)&/span&
&span class=&p&&.&/span&&span class=&nx&&bundle&/span&&span class=&p&&()&/span&
&span class=&p&&.&/span&&span class=&nx&&pipe&/span&&span class=&p&&(&/span&&span class=&nx&&source&/span&&span class=&p&&(&/span&&span class=&nx&&versionName&/span&&span class=&p&&))&/span&
&span class=&p&&.&/span&&span class=&nx&&pipe&/span&&span class=&p&&(&/span&&span class=&nx&&buffer&/span&&span class=&p&&())&/span&
&span class=&p&&.&/span&&span class=&nx&&pipe&/span&&span class=&p&&(&/span&&span class=&nx&&concat&/span&&span class=&p&&(&/span&&span class=&nx&&versionName&/span& &span class=&o&&+&/span& &span class=&s1&&'.js'&/span&&span class=&p&&))&/span&
&span class=&p&&.&/span&&span class=&nx&&pipe&/span&&span class=&p&&(&/span&&span class=&nx&&gulp&/span&&span class=&p&&.&/span&&span class=&nx&&dest&/span&&span class=&p&&(&/span&&span class=&s1&&'./prd'&/span&&span class=&p&&))&/span&
&span class=&p&&.&/span&&span class=&nx&&pipe&/span&&span class=&p&&(&/span&&span class=&nx&&uglify&/span&&span class=&p&&())&/span&
&span class=&p&&.&/span&&span class=&nx&&pipe&/span&&span class=&p&&(&/span&&span class=&nx&&concat&/span&&span class=&p&&(&/span&&span class=&nx&&versionName&/span& &span class=&o&&+&/span& &span class=&s1&&'.min.js'&/span&&span class=&p&&))&/span&
&span class=&p&&.&/span&&span class=&nx&&pipe&/span&&span class=&p&&(&/span&&span class=&nx&&gulp&/span&&span class=&p&&.&/span&&span class=&nx&&dest&/span&&span class=&p&&(&/span&&span class=&s1&&'./prd'&/span&&span class=&p&&));&/span&
&span class=&p&&});&/span&
&/code&&/pre&&/div&&br&确定好了功能划分和构建方式,下面我们就来实现每一个功能模块:&br&&br&&b&入口文件 mcmd.js&/b&&br&&br&将我们的 cmd loader 挂在 window.mcmd 上,把 define 方法也挂在 window.define 上,初始化其他的方法和配置。&br&&br&&div class=&highlight&&&pre&&code class=&language-js&&&span class=&kd&&var&/span& &span class=&nx&&g&/span& &span class=&o&&=&/span& &span class=&nb&&window&/span&&span class=&p&&;&/span&
&span class=&nx&&g&/span&&span class=&p&&.&/span&&span class=&nx&&define&/span& &span class=&o&&=&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'./define'&/span&&span class=&p&&);&/span&
&span class=&nx&&g&/span&&span class=&p&&.&/span&&span class=&nx&&mcmd&/span& &span class=&o&&=&/span& &span class=&p&&{&/span&
&span class=&nx&&use&/span&&span class=&o&&:&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'./use'&/span&&span class=&p&&),&/span&
&span class=&nx&&require&/span&&span class=&o&&:&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'./require'&/span&&span class=&p&&),&/span&
&span class=&c1&&// 模块缓存&/span&
&span class=&nx&&modules&/span&&span class=&o&&:&/span& &span class=&p&&{},&/span&
&span class=&c1&&// 默认配置&/span&
&span class=&nx&&config&/span&&span class=&o&&:&/span& &span class=&p&&{&/span&
&span class=&nx&&root&/span&&span class=&o&&:&/span& &span class=&s1&&'/'&/span&
&span class=&p&&},&/span&
&span class=&c1&&// 修改配置&/span&
&span class=&nx&&setConfig&/span&&span class=&o&&:&/span& &span class=&kd&&function&/span& &span class=&p&&(&/span&&span class=&nx&&obj&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&for&/span& &span class=&p&&(&/span&&span class=&kd&&var&/span& &span class=&nx&&key&/span& &span class=&k&&in&/span& &span class=&nx&&obj&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&config&/span&&span class=&p&&[&/span&&span class=&nx&&key&/span&&span class=&p&&]&/span& &span class=&o&&=&/span& &span class=&nx&&obj&/span&&span class=&p&&[&/span&&span class=&nx&&key&/span&&span class=&p&&];&/span&
&span class=&p&&}&/span&
&span class=&p&&},&/span&
&span class=&c1&&// 模块状态常量&/span&
&span class=&nx&&MODULE_STATUS&/span&&span class=&o&&:&/span& &span class=&p&&{&/span&
&span class=&nx&&PENDDING&/span&&span class=&o&&:&/span& &span class=&mi&&0&/span&&span class=&p&&,&/span&
&span class=&nx&&LOADING&/span&&span class=&o&&:&/span& &span class=&mi&&1&/span&&span class=&p&&,&/span&
&span class=&nx&&COMPLETED&/span&&span class=&o&&:&/span& &span class=&mi&&2&/span&&span class=&p&&,&/span&
&span class=&nx&&ERROR&/span&&span class=&o&&:&/span& &span class=&mi&&3&/span&
&span class=&p&&}&/span&
&span class=&p&&};&/span&
&/code&&/pre&&/div&&br&&b&use.js&/b&&br&&br&实现了 mcmd.use 方法,接收两个参数,第一个是id或者id数组,第二个是回调函数。内部会使用 load.js 来获取模块,并通过 promise 来处理获取多个模块的并发异步场景。&br&&br&&div class=&highlight&&&pre&&code class=&language-text&&var Promise = require('./promise');
var load = require('./load');
module.exports = function use(ids, callback) {
if (!Array.isArray(ids)) {
ids = [ids]
Promise.all(ids.map(function (id) {
return load(mcmd.config.root + id);
})).then(function (list) {
if (typeof callback === 'function') {
callback.apply(window, list);
}, function (errorInfo) {
throw errorI
&/code&&/pre&&/div&&br&&b&load.js&/b&&br&&br&获取一个模块,并绑定事件,接收两个参数,一个是模块id,一个是回调函数,并返回一个 promise 对象。当模块 complete(加载完成)时,执行回调,同时 resolve 返回的 promise 对象。&br&&br&&div class=&highlight&&&pre&&code class=&language-js&&&span class=&kd&&var&/span& &span class=&nx&&Promise&/span& &span class=&o&&=&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'./promise'&/span&&span class=&p&&);&/span&
&span class=&kd&&var&/span& &span class=&nx&&Module&/span& &span class=&o&&=&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'./module'&/span&&span class=&p&&);&/span&
&span class=&kd&&var&/span& &span class=&nx&&util&/span& &span class=&o&&=&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'./util'&/span&&span class=&p&&);&/span&
&span class=&nx&&module&/span&&span class=&p&&.&/span&&span class=&nx&&exports&/span& &span class=&o&&=&/span& &span class=&kd&&function&/span& &span class=&p&&(&/span&&span class=&nx&&id&/span&&span class=&p&&,&/span& &span class=&nx&&callback&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&k&&new&/span& &span class=&nx&&Promise&/span&&span class=&p&&(&/span&&span class=&kd&&function&/span& &span class=&p&&(&/span&&span class=&nx&&resolve&/span&&span class=&p&&,&/span& &span class=&nx&&reject&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&kd&&var&/span& &span class=&nx&&mod&/span& &span class=&o&&=&/span&
&span class=&nx&&mcmd&/span&&span class=&p&&.&/span&&span class=&nx&&modules&/span&&span class=&p&&[&/span&&span class=&nx&&id&/span&&span class=&p&&]&/span& &span class=&o&&||&/span& &span class=&nx&&Module&/span&&span class=&p&&.&/span&&span class=&nx&&create&/span&&span class=&p&&(&/span&&span class=&nx&&id&/span&&span class=&p&&);&/span&
&span class=&nx&&mod&/span&&span class=&p&&.&/span&&span class=&nx&&on&/span&&span class=&p&&(&/span&&span class=&s1&&'complete'&/span&&span class=&p&&,&/span& &span class=&kd&&function&/span& &span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&kd&&var&/span& &span class=&nx&&exp&/span& &span class=&o&&=&/span& &span class=&nx&&util&/span&&span class=&p&&.&/span&&span class=&nx&&getModuleExports&/span&&span class=&p&&(&/span&&span class=&nx&&mod&/span&&span class=&p&&);&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&k&&typeof&/span& &span class=&nx&&callback&/span& &span class=&o&&===&/span& &span class=&s1&&'function'&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&nx&&callback&/span&&span class=&p&&(&/span&&span class=&nx&&exp&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&nx&&resolve&/span&&span class=&p&&(&/span&&span class=&nx&&exp&/span&&span class=&p&&);&/span&
&span class=&p&&});&/span&
&span class=&nx&&mod&/span&&span class=&p&&.&/span&&span class=&nx&&on&/span&&span class=&p&&(&/span&&span class=&s1&&'error'&/span&&span class=&p&&,&/span& &span class=&nx&&reject&/span&&span class=&p&&);&/span&
&span class=&p&&});&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&br&&b&promise.js&/b&&br&&br&详见: &a href=&http://annn.me/ecmascript6-promise& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&如何实现一个ECMAScript 6 的promise补丁 |
安·记&i class=&icon-external&&&/i&&/a&&br&&br&&b&module.js&/b&&br&&br&模块的构造函数,实现了模块的创建,加载,事件传递,状态维护等。&br&&br&&div class=&highlight&&&pre&&code class=&language-js&&&span class=&c1&&// 构造函数&/span&
&span class=&kd&&function&/span& &span class=&nx&&Module&/span&&span class=&p&&(&/span&&span class=&nx&&id&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&nx&&mcmd&/span&&span class=&p&&.&/span&&span class=&nx&&modules&/span&&span class=&p&&[&/span&&span class=&nx&&id&/span&&span class=&p&&]&/span& &span class=&o&&=&/span& &span class=&k&&this&/span&&span class=&p&&;&/span& &span class=&c1&&// 缓存模块&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&id&/span& &span class=&o&&=&/span& &span class=&nx&&id&/span&&span class=&p&&;&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&status&/span& &span class=&o&&=&/span& &span class=&nx&&mcmd&/span&&span class=&p&&.&/span&&span class=&nx&&MODULE_STATUS&/span&&span class=&p&&.&/span&&span class=&nx&&PENDDING&/span&&span class=&p&&;&/span& &span class=&c1&&// 状态&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&factory&/span& &span class=&o&&=&/span& &span class=&kc&&null&/span&&span class=&p&&;&/span&
&span class=&c1&&// 执行代码&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&dependences&/span& &span class=&o&&=&/span& &span class=&kc&&null&/span&&span class=&p&&;&/span&
&span class=&c1&&//依赖&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&callbacks&/span& &span class=&o&&=&/span& &span class=&p&&{};&/span&
&span class=&c1&&// 绑定的事件回调函数&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&load&/span&&span class=&p&&();&/span&
&span class=&p&&}&/span&
&span class=&c1&&// 静态方法创建模块&/span&
&span class=&nx&&Module&/span&&span class=&p&&.&/span&&span class=&nx&&create&/span& &span class=&o&&=&/span& &span class=&kd&&function&/span& &span class=&p&&(&/span&&span class=&nx&&id&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&k&&new&/span& &span class=&nx&&Module&/span&&span class=&p&&(&/span&&span class=&nx&&id&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&c1&&// 通过创建 script 标签异步加载模块&/span&
&span class=&nx&&Module&/span&&span class=&p&&.&/span&&span class=&nx&&prototype&/span&&span class=&p&&.&/span&&span class=&nx&&load&/span& &span class=&o&&=&/span& &span class=&kd&&function&/span& &span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&kd&&var&/span& &span class=&nx&&id&/span& &span class=&o&&=&/span& &span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&id&/span&&span class=&p&&;&/span&
&span class=&kd&&var&/span& &span class=&nx&&script&/span& &span class=&o&&=&/span& &span class=&nb&&document&/span&&span class=&p&&.&/span&&span class=&nx&&createElement&/span&&span class=&p&&(&/span&&span class=&s1&&'script'&/span&&span class=&p&&);&/span&
&span class=&nx&&script&/span&&span class=&p&&.&/span&&span class=&nx&&src&/span& &span class=&o&&=&/span& &span class=&nx&&id&/span&&span class=&p&&;&/span&
&span class=&nx&&script&/span&&span class=&p&&.&/span&&span class=&nx&&onerror&/span& &span class=&o&&=&/span& &span class=&kd&&function&/span& &span class=&p&&(&/span&&span class=&nx&&event&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&setStatus&/span&&span class=&p&&(&/span&&span class=&nx&&mcmd&/span&&span class=&p&&.&/span&&span class=&nx&&MODULE_STATUS&/span&&span class=&p&&.&/span&&span class=&nx&&ERROR&/span&&span class=&p&&,&/span& &span class=&p&&{&/span&
&span class=&nx&&id&/span&&span class=&o&&:&/span& &span class=&nx&&id&/span&&span class=&p&&,&/span&
&span class=&nx&&error&/span&&span class=&o&&:&/span& &span class=&p&&(&/span&&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&error&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&nb&&Error&/span&&span class=&p&&(&/span&&span class=&s1&&'module can not load.'&/span&&span class=&p&&))&/span&
&span class=&p&&});&/span&
&span class=&p&&}.&/span&&span class=&nx&&bind&/span&&span class=&p&&(&/span&&span class=&k&&this&/span&&span class=&p&&);&/span&
&span class=&nb&&document&/span&&span class=&p&&.&/span&&span class=&nx&&head&/span&&span class=&p&&.&/span&&span class=&nx&&appendChild&/span&&span class=&p&&(&/span&&span class=&nx&&script&/span&&span class=&p&&);&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&setStatus&/span&&span class=&p&&(&/span&&span class=&nx&&mcmd&/span&&span class=&p&&.&/span&&span class=&nx&&MODULE_STATUS&/span&&span class=&p&&.&/span&&span class=&nx&&LOADING&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&c1&&// 事件绑定方法&/span&
&span class=&nx&&Module&/span&&span class=&p&&.&/span&&span class=&nx&&prototype&/span&&span class=&p&&.&/span&&span class=&nx&&on&/span& &span class=&o&&=&/span& &span class=&kd&&function&/span& &span class=&p&&(&/span&&span class=&nx&&event&/span&&span class=&p&&,&/span& &span class=&nx&&callback&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&p&&(&/span&&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&callbacks&/span&&span class=&p&&[&/span&&span class=&nx&&event&/span&&span class=&p&&]&/span& &span class=&o&&||&/span& &span class=&p&&(&/span&&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&callbacks&/span&&span class=&p&&[&/span&&span class=&nx&&event&/span&&span class=&p&&]&/span& &span class=&o&&=&/span& &span class=&p&&[])).&/span&&span class=&nx&&push&/span&&span class=&p&&(&/span&&span class=&nx&&callback&/span&&span class=&p&&);&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&
&span class=&p&&(&/span&&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&status&/span& &span class=&o&&===&/span& &span class=&nx&&mcmd&/span&&span class=&p&&.&/span&&span class=&nx&&MODULE_STATUS&/span&&span class=&p&&.&/span&&span class=&nx&&LOADING&/span& &span class=&o&&&&&/span& &span class=&nx&&event&/span& &span class=&o&&===&/span& &span class=&s1&&'load'&/span&&span class=&p&&)&/span& &span class=&o&&||&/span&
&span class=&p&&(&/span&&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&status&/span& &span class=&o&&===&/span& &span class=&nx&&mcmd&/span&&span class=&p&&.&/span&&span class=&nx&&MODULE_STATUS&/span&&span class=&p&&.&/span&&span class=&nx&&COMPLETED&/span& &span class=&o&&&&&/span& &span class=&nx&&event&/span& &span class=&o&&===&/span& &span class=&s1&&'complete'&/span&&span class=&p&&)&/span&
&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&nx&&callback&/span&&span class=&p&&(&/span&&span class=&k&&this&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&status&/span& &span class=&o&&===&/span& &span class=&nx&&mcmd&/span&&span class=&p&&.&/span&&span class=&nx&&MODULE_STATUS&/span&&span class=&p&&.&/span&&span class=&nx&&ERROR&/span& &span class=&o&&&&&/span& &span class=&nx&&event&/span& &span class=&o&&===&/span& &span class=&s1&&'error'&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&nx&&callback&/span&&span class=&p&&(&/span&&span class=&k&&this&/span&&span class=&p&&,&/span& &span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&error&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&c1&&// 事件触发方法&/span&
&span class=&nx&&Module&/span&&span class=&p&&.&/span&&span class=&nx&&prototype&/span&&span class=&p&&.&/span&&span class=&nx&&fire&/span& &span class=&o&&=&/span& &span class=&kd&&function&/span& &span class=&p&&(&/span&&span class=&nx&&event&/span&&span class=&p&&,&/span& &span class=&nx&&arg&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&p&&(&/span&&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&callbacks&/span&&span class=&p&&[&/span&&span class=&nx&&event&/span&&span class=&p&&]&/span& &span class=&o&&||&/span& &span class=&p&&[]).&/span&&span class=&nx&&forEach&/span&&span class=&p&&(&/span&&span class=&kd&&function&/span& &span class=&p&&(&/span&&span class=&nx&&callback&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&nx&&callback&/span&&span class=&p&&(&/span&&span class=&nx&&arg&/span& &span class=&o&&||&/span& &span class=&k&&this&/span&&span class=&p&&);&/span&
&span class=&p&&}.&/span&&span class=&nx&&bind&/span&&span class=&p&&(&/span&&span class=&k&&this&/span&&span class=&p&&));&/span&
&span class=&p&&}&/span&
&span class=&c1&&// 设置状态方法,并抛出相应的事件&/span&
&span class=&nx&&Module&/span&&span class=&p&&.&/span&&span class=&nx&&prototype&/span&&span class=&p&&.&/span&&span class=&nx&&setStatus&/span& &span class=&o&&=&/span& &span class=&kd&&function&/span& &span class=&p&&(&/span&&span class=&nx&&status&/span&&span class=&p&&,&/span& &span class=&nx&&info&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&status&/span& &span class=&o&&!==&/span& &span class=&nx&&status&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&status&/span& &span class=&o&&=&/span& &span class=&nx&&status&/span&&span class=&p&&;&/span&
&span class=&k&&switch&/span& &span class=&p&&(&/span&&span class=&nx&&status&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&case&/span& &span class=&nx&&mcmd&/span&&span class=&p&&.&/span&&span class=&nx&&MODULE_STATUS&/span&&span class=&p&&.&/span&&span class=&nx&&LOADING&/span&&span class=&o&&:&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&fire&/span&&span class=&p&&(&/span&&span class=&s1&&'load'&/span&&span class=&p&&);&/span&
&span class=&k&&break&/span&&span class=&p&&;&/span&
&span class=&k&&case&/span& &span class=&nx&&mcmd&/span&&span class=&p&&.&/span&&span class=&nx&&MODULE_STATUS&/span&&span class=&p&&.&/span&&span class=&nx&&COMPLETED&/span&&span class=&o&&:&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&fire&/span&&span class=&p&&(&/span&&span class=&s1&&'complete'&/span&&span class=&p&&);&/span&
&span class=&k&&break&/span&&span class=&p&&;&/span&
&span class=&k&&case&/span& &span class=&nx&&mcmd&/span&&span class=&p&&.&/span&&span class=&nx&&MODULE_STATUS&/span&&span class=&p&&.&/span&&span class=&nx&&ERROR&/span&&span class=&o&&:&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&nx&&fire&/span&&span class=&p&&(&/span&&span class=&s1&&'error'&/span&&span class=&p&&,&/span& &span class=&nx&&info&/span&&span class=&p&&);&/span&
&span class=&k&&break&/span&&span class=&p&&;&/span&
&span class=&k&&default&/span&&span class=&o&&:&/span&
&span class=&k&&break&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&nx&&module&/span&&span class=&p&&.&/span&&span class=&nx&&exports&/span& &span class=&o&&=&/span& &span class=&nx&&Module&/span&&span class=&p&&;&/span&
&/code&&/pre&&/div&&br&&b&define.js&/b&&br&&br&实现 window.define 方法。接收一个参数 factory(cmd规范中不止一个,为了保持简单,我们只实现一个),即模块的代码包裹函数。通过 getCurrentScript 这个函数获取到当前执行脚本的 script 节点 src ,提取出模块 id ,找到模块对象。然后提取出 factory 中的依赖子模块,如果没有依赖,则直接触发模块的 &complete& 事件, 如果有依赖,则创建依赖的模块,绑定事件并加载,等依赖的模块加载完成后,再触发 &complete& 事件。&br&&br&&div class=&highlight&&&pre&&code class=&language-js&&&span class=&kd&&var&/span& &span class=&nx&&util&/span& &span class=&o&&=&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'./util'&/span&&span class=&p&&);&/span&
&span class=&kd&&var&/span& &span class=&nx&&Promise&/span& &span class=&o&&=&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'./promise'&/span&&span class=&p&&);&/span&
&span class=&kd&&var&/span& &span class=&nx&&Module&/span& &span class=&o&&=&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'./module'&/span&&span class=&p&&);&/span&
&span class=&nx&&module&/span&&span class=&p&&.&/span&&span class=&nx&&exports&/span& &span class=&o&&=&/span& &span class=&kd&&function&/span& &span class=&p&&(&/span&&span class=&nx&&factory&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&kd&&var&/span& &span class=&nx&&id&/span& &span class=&o&&=&/span& &span class=&nx&&getCurrentScript&/span&&span class=&p&&().&/span&&span class=&nx&&replace&/span&&span class=&p&&(&/span&&span class=&nx&&location&/span&&span class=&p&&.&/span&&span class=&nx&&origin&/span&&span class=&p&&,&/span& &span class=&s1&&''&/span&&span class=&p&&);&/span&
&span class=&kd&&var&/span& &span class=&nx&&mod&/span& &span class=&o&&=&/span& &span class=&nx&&mcmd&/span&&span class=&p&&.&/span&&span class=&nx&&modules&/span&&span class=&p&&[&/span&&span class=&nx&&id&/span&&span class=&p&&];&/span&
&span class=&kd&&var&/span& &span class=&nx&&dependences&/span& &span class=&o&&=&/span& &span class=&nx&&mod&/span&&span class=&p&&.&/span&&span class=&nx&&dependences&/span& &span class=&o&&=&/span& &span class=&nx&&getDenpendence&/span&&span class=&p&&(&/span&&span class=&nx&&factory&/span&&span class=&p&&.&/span&&span class=&nx&&toString&/span&&span class=&p&&());&/span&
&span class=&nx&&mod&/span&&span class=&p&&.&/span&&span class=&nx&&factory&/span& &span class=&o&&=&/span& &span class=&nx&&factory&/span&&span class=&p&&;&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&nx&&dependences&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&nx&&Promise&/span&&span class=&p&&.&/span&&span class=&nx&&all&/span&&span class=&p&&(&/span&&span class=&nx&&dependences&/span&&span class=&p&&.&/span&&span class=&nx&&map&/span&&span class=&p&&(&/span&&span class=&kd&&function&/span& &span class=&p&&(&/span&&span class=&nx&&id&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&k&&new&/span& &span class=&nx&&Promise&/span&&span class=&p&&(&/span&&span class=&kd&&function&/span& &span class=&p&&(&/span&&span class=&nx&&resolve&/span&&span class=&p&&,&/span& &span class=&nx&&reject&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&nx&&id&/span& &span class=&o&&=&/span& &span class=&nx&&mcmd&/span&&span class=&p&&.&/span&&span class=&nx&&config&/span&&span class=&p&&.&/span&&span class=&nx&&root&/span& &span class=&o&&+&/span& &span class=&nx&&id&/span&&span class=&p&&;&/span&
&span class=&kd&&var&/span& &span class=&nx&&depMode&/span& &span class=&o&&=&/span& &span class=&nx&&mcmd&/span&&span class=&p&&.&/span&&span class=&nx&&modules&/span&&span class=&p&&[&/span&&span class=&nx&&id&/span&&span class=&p&&]&/span& &span class=&o&&||&/span& &span class=&nx&&Module&/span&&span class=&p&&.&/span&&span class=&nx&&create&/span&&span class=&p&&(&/span&&span class=&nx&&id&/span&&span class=&p&&);&/span&
&span class=&nx&&depMode&/span&&span class=&p&&.&/span&&span class=&nx&&on&/span&&span class=&p&&(&/span&&span class=&s1&&'complete'&/span&&span class=&p&&,&/span& &span class=&nx&&resolve&/span&&span class=&p&&);&/span&
&span class=&nx&&depMode&/span&&span class=&p&&.&/span&&span class=&nx&&on&/span&&span class=&p&&(&/span&&span class=&s1&&'error'&/span&&span class=&p&&,&/span& &span class=&nx&&reject&/span&&span class=&p&&);&/span&
&span class=&p&&});&/span&
&span class=&p&&})).&/span&&span class=&nx&&then&/span&&span class=&p&&(&/span&&span class=&kd&&function&/span& &span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&nx&&mod&/span&&span class=&p&&.&/span&&span class=&nx&&setStatus&/span&&span class=&p&&(&/span&&span class=&nx&&mcmd&/span&&span class=&p&&.&/span&&span class=&nx&&MODULE_STATUS&/span&&span class=&p&&.&/span&&span class=&nx&&COMPLETED&/span&&span class=&p&&);&/span&
&span class=&p&&},&/span& &span class=&kd&&function&/span& &span class=&p&&(&/span&&span class=&nx&&error&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&nx&&mod&/span&&span class=&p&&.&/span&&span class=&nx&&setStatus&/span&&span class=&p&&(&/span&&span class=&nx&&mcmd&/span&&span class=&p&&.&/span&&span class=&nx&&MODULE_STATUS&/span&&span class=&p&&.&/span&&span class=&nx&&ERROR&/span&&span class=&p&&,&/span& &span class=&nx&&error&/span&&span class=&p&&);&/span&
&span class=&p&&});&/span&
&span class=&p&&}&/span&
&span class=&k&&else&/span& &span class=&p&&{&/span&
&span class=&nx&&mod&/span&&span class=&p&&.&/span&&span class=&nx&&setStatus&/span&&span class=&p&&(&/span&&span class=&nx&&mcmd&/span&&span class=&p&&.&/span&&span class=&nx&&MODULE_STATUS&/span&&span class=&p&&.&/span&&span class=&nx&&COMPLETED&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&c1&&// 获取当前执行的script节点&/span&
&span class=&c1&&// 参考 getCurrentScript的改进&/span&
&span class=&kd&&function&/span& &span class=&nx&&getCurrentScript&/span&&span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&kd&&var&/span& &span class=&nx&&doc&/span& &span class=&o&&=&/span& &span class=&nb&&document&/span&&span class=&p&&;&/span&
&span class=&k&&if&/span&&span class=&p&&(&/span&&span class=&nx&&doc&/span&&span class=&p&&.&/span&&span class=&nx&&currentScript&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&nx&&doc&/span&&span class=&p&&.&/span&&span class=&nx&&currentScript&/span&&span class=&p&&.&/span&&span class=&nx&&src&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&span class=&kd&&var&/span& &span class=&nx&&stack&/span&&span class=&p&&;&/span&
&span class=&k&&try&/span& &span class=&p&&{&/span&
&span class=&nx&&a&/span&&span class=&p&&.&/span&&span class=&nx&&b&/span&&span class=&p&&.&/span&&span class=&nx&&c&/span&&span class=&p&&();&/span&
&span class=&p&&}&/span& &span class=&k&&catch&/span&&span class=&p&&(&/span&&span class=&nx&&e&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&nx&&stack&/span& &span class=&o&&=&/span& &span class=&nx&&e&/span&&span class=&p&&.&/span&&span class=&nx&&stack&/span&&span class=&p&&;&/span&
&span class=&k&&if&/span&&span class=&p&&(&/span&&span class=&o&&!&/span&&span class=&nx&&stack&/span& &span class=&o&&&&&/span& &span class=&nb&&window&/span&&span class=&p&&.&/span&&span class=&nx&&opera&/span&&span class=&p&&){&/span&
&span class=&nx&&stack&/span& &span class=&o&&=&/span& &span class=&p&&(&/span&&span class=&nb&&String&/span&&span class=&p&&(&/span&&span class=&nx&&e&/span&&span class=&p&&).&/span&&span class=&nx&&match&/span&&span class=&p&&(&/span&&span class=&sr&&/of linked script \S+/g&/span&&span class=&p&&)&/span& &span class=&o&&||&/span& &span class=&p&&[]).&/span&&span class=&nx&&join&/span&&span class=&p&&(&/span&&span class=&s2&&& &&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&k&&if&/span&&span class=&p&&(&/span&&span class=&nx&&stack&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&nx&&stack&/span& &span class=&o&&=&/span& &span class=&nx&&stack&/span&&span class=&p&&.&/span&&span class=&nx&&split&/span&&span class=&p&&(&/span& &span class=&sr&&/[@ ]/g&/span&&span class=&p&&).&/span&&span class=&nx&&pop&/span&&span class=&p&&();&/span&
&span class=&nx&&stack&/span& &span class=&o&&=&/span& &span class=&nx&&stack&/span&&span class=&p&&[&/span&&span class=&mi&&0&/span&&span class=&p&&]&/span& &span class=&o&&==&/span& &span class=&s2&&&(&&/span& &span class=&o&&?&/span& &span class=&nx&&stack&/span&&span class=&p&&.&/span&&span class=&nx&&slice&/span&&span class=&p&&(&/span&&span class=&mi&&1&/span&&span class=&p&&,&/span&&span class=&o&&-&/span&&span class=&mi&&1&/span&&span class=&p&&)&/span& &span class=&o&&:&/span& &span class=&nx&&stack&/span&&span class=&p&&;&/span&
&span class=&k&&return&/span& &span class=&nx&&stack&/span&&span class=&p&&.&/span&&span class=&nx&&replace&/span&&span class=&p&&(&/span&&span class=&sr&&/(:\d+)?:\d+$/i&/span&&span class=&p&&,&/span& &span class=&s2&&&&&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&kd&&var&/span& &span class=&nx&&nodes&/span& &span class=&o&&=&/span& &span class=&nx&&head&/span&&span class=&p&&.&/span&&span class=&nx&&getElementsByTagName&/span&&span class=&p&&(&/span&&span class=&s2&&&script&&/span&&span class=&p&&);&/span&
&span class=&k&&for&/span&&span class=&p&&(&/span&&span class=&kd&&var&/span& &span class=&nx&&i&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&&span class=&p&&,&/span& &span class=&nx&&node&/span&&span class=&p&&;&/span& &span class=&nx&&node&/span& &span class=&o&&=&/span& &span class=&nx&&nodes&/span&&span class=&p&&[&/span&&span class=&nx&&i&/span&&span class=&o&&++&/span&&span class=&p&&];)&/span& &span class=&p&&{&/span&
&span class=&k&&if&/span&&span class=&p&&(&/span&&span class=&nx&&node&/span&&span class=&p&&.&/span&&span class=&nx&&readyState&/span& &span class=&o&&===&/span& &span class=&s2&&&interactive&&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&nx&&node&/span&&span class=&p&&.&/span&&span class=&nx&&className&/span& &span class=&o&&=&/span& &span class=&nx&&node&/span&&span class=&p&&.&/span&&span class=&nx&&src&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&c1&&// 解析依赖,这里只做简单的提取,实际需要考虑更多情况,参考seajs&/span&
&span class=&kd&&function&/span& &span class=&nx&&getDenpendence&/span&&span class=&p&&(&/span&&span class=&nx&&factory&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&kd&&var&/span& &span class=&nx&&list&/span& &span class=&o&&=&/span& &span class=&nx&&factory&/span&&span class=&p&&.&/span&&span class=&nx&&match&/span&&span class=&p&&(&/span&&span class=&sr&&/require\(.+?\)/g&/span&&span class=&p&&);&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&nx&&list&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&nx&&list&/span& &span class=&o&&=&/span& &span class=&nx&&list&/span&&span class=&p&&.&/span&&span class=&nx&&map&/span&&span class=&p&&(&/span&&span class=&kd&&function&/span& &span class=&p&&(&/span&&span class=&nx&&dep&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&nx&&dep&/span&&span class=&p&&.&/span&&span class=&nx&&replace&/span&&span class=&p&&(&/span&&span class=&sr&&/(^require\(['&])|(['&]\)$)/g&/span&&span class=&p&&,&/span& &span class=&s1&&''&/span&&span class=&p&&);&/span&
&span class=&p&&});&/span&
&span class=&p&&}&/span&
&span class=&k&&return&/span& &span class=&nx&&list&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&br&&br&require.js
&br&返回模块的 exports 属性, 这里通过封装的 util.getModuleExports 方法获取并返回。 &br&&br&&div class=&highlight&&&pre&&code class=&language-text&&
var util = require('./util');
module.exports = function (id) {
id = mcmd.config.root +
var mod = mcmd.modules[id];
if (mod) {
return util.getModuleExports(mod);
throw 'can not get module by from:' +
module.exports.async = function (ids, callback) {
mcmd.use(ids, callback);
&/code&&/pre&&/div&&br&&b&util.js&/b&&br&&br&这里只有一个 getModuleExports 方法, 接收一个模块,返回模块的接口。当模块的 exports 属性不存在时,说明模块的 factory 没有被执行过。这时我们需要执行下 factory,传入 require, 创建的exports,以及 module 本身作为参数。最后获取模块的暴露的数据并返回。&br&&br&&div class=&highlight&&&pre&&code class=&language-java&&&span class=&n&&module&/span&&span class=&o&&.&/span&&span class=&na&&exports&/span& &span class=&o&&=&/span& &span class=&o&&{&/span&
&span class=&n&&getModuleExports&/span&&span class=&o&&:&/span& &span class=&n&&function&/span& &span class=&o&&(&/span&&span class=&n&&mod&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&if&/span& &span class=&o&&(!&/span&&span class=&n&&mod&/span&&span class=&o&&.&/span&&span class=&na&&exports&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&mod&/span&&span class=&o&&.&/span&&span class=&na&&exports&/span& &span class=&o&&=&/span& &span class=&o&&{};&/span&
&span class=&n&&mod&/span&&span class=&o&&.&/span&&span class=&na&&factory&/span&&span class=&o&&(&/span&&span class=&n&&mcmd&/span&&span class=&o&&.&/span&&span class=&na&&require&/span&&span class=&o&&,&/span& &span class=&n&&mod&/span&&span class=&o&&.&/span&&span class=&na&&exports&/span&&span class=&o&&,&/span& &span class=&n&&mod&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&k&&return&/span& &span class=&n&&mod&/span&&span class=&o&&.&/span&&span class=&na&&exports&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&o&&};&/span&
&/code&&/pre&&/div&&br&这样,整个 cmd loader 就基本完成了。这只是一个非常基础的模块加载器,主要是为了理解 cmd 的原理和实现方式,对于生产环境,推荐使用成熟的 seajs。&br&&br&整个 mcmd 项目我都放在了 github 上,大家可以去看:&a href=&/hanan198501/mcmd& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&/hanan198501/&/span&&span class=&invisible&&mcmd&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&。&br&原文地址:&a href=&http://annn.me/how-to-realize-cmd-loader/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&如何实现一个 CMD 模块加载器 |
安·记&i class=&icon-external&&&/i&&/a&
cmd 对于 nodejs 的使用者来说更加友好,使得类似 commonJS 模块的写法可以在浏览器中使用,同时解决了浏览器中模块异步加载的困扰。关于 cmd 更详细的内容可以移步我们可以通过实现一…}

我要回帖

更多关于 requirejs 如何使用 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信