dojo.require()的相关理解
Dojo 提供了一个非常强大的javascript控件库. 在使用dojo之前,用户基本上不需要具备任何基础知识. 你可以用script远程链接到dojo(dojo.js), 也可以把dojo.js下载到本地并用script标签加载.
如果你不太了解dojo, 可以参考一下如下资料:
大体上,dojo.js和jquery.js 或者 prototype js, 里面有很多开发web应用的常用的特性: 包括:
- JavaScript Language Helpers
- Object 工具
- Array 工具
- DOM 操作
- 标准的事件机制
- Ajax & 跨域请
- JSON 工具
- 简单特效
- 浏览器兼容
不仅如此, dojo还有很多其他javascript库(jquery, ext等等)所不具有的功能. 其中一个很重要的功能就是模块化的机制 - 模块系统(dojo.require()
). JavaScript 和 浏览器本身以及其他的javascript库并不支持这种特性, dojo很好的解决了这种问题.
模块系统
dojo.require('my.module')
用于加载javascript文件, 功能类似于script标签的作用.
假设你有一个本地的开发环境,目录结构如下:(http://localhost:8888
.)
index.html
是一个包含 dojo.js 简单页面
.
<html lang=”en”>
<head>
<meta charset=”utf-8″ />
<title>Dojo</title>
</head>
<body>
<script src=”dojo/dojo.js”></script>
</body>
</html>
假设我们要用Flickr API获取数据, 这时候,我们就要用到跨域请求, 但是这些功能模块并不是在dojo base库里面, 我们需要另外加载所需的dojo模块:
<html lang=”en”>
<head>
<meta charset=”utf-8″ />
<title>Dojo</title>
</head>
<body>
<script src=”/dojo/dojo.js”></script>
<script src=”/dojo/io/script.js”></script>
</body>
</html>
这里我们可以用script标签解决这种问题, 同样还有另外一种方式, 这种方式体现了模块系统的宗旨: 我们用dojo.require()
加载 dojo.io.script
<html lang=”en”>
<head>
<meta charset=”utf-8″ />
<title>Dojo</title>
</head>
<body>
<script src=”/dojo/dojo.js”></script>
<script>
dojo.require(”dojo.io.script”);
//Note: do not include the .js
</script>
</body>
</html>
通过
dojo.require()
我们获得了一个模块系统, 它提供了一系列我们开发复杂web2.0页面所需要的组件. 接下来的内容我们会着重介绍模块系统的特性:
- 缓存管理
- 命名空间管理
- 路径管理
- 依赖管理
首先, dojo.require()会避免重复加载, 如果script脚本被浏览器缓存了, dojo会调用缓存的资源从而避免不必要的http请求, 事实上,你可以随便调用
dojo.require(), 不管调用了多少
dojo.require(), dojo都会保证同样的模块只会被加载一次.
我们也可以创建自己的模块. 让我们回到Flickr API的例子, 我们要开发一个用Flickr数据的大型web应用, 我们需要能很好的组织和管理这些javascript代码. 归根结底,我们需要创建名为flickrApp的命名空间用于保存所有该应用的逻辑功能. 为了达到这个目的, 我们更新原有的目录结构, 创建一个flickrApp.js文件:
flickrApp.js看起来似乎仅仅是一个js文件, 但如果你用dojo的眼光来看他, 你会发现他其实应该是一个模块, 为了让dojo识别他是这个模块, 我们用
dojo.provide()
方法初始化这个js文件,将其变为一个dojo的模块. 我们加入如下代码到 flickrApp.js 文件中:
- dojo.provide(”flickrApp “); //similar to doing flickrApp = {};
dojo.provide()
创建了一个以你传入的字符串(flickrApp
)命名的对象结构(名字空间), 我们这里是创建了一个名为flickrApp的对象, 该对象创建后, 我们便可以像定义该对象的各个属性一样来定义该应用(
flickrApp
)
的各个方面, 下面是 flickrApp.js 一个例子:
- dojo.provide(”flickrApp”);
- //start creating the application logic for my flickr app
- flickrApp.getData = function(){};
dojo.require()
来加载我们自定义的模块到HTML页面上:<html lang=”en”>
<head>
<meta charset=”utf-8″ />
<title>Dojo</title>
</head>
<body>
<script src=”/dojo/dojo.js”></script>
<script>
dojo.require(”dojo.io.script”);
dojo.require(”flickrApp”);
</script>
</body>
</html>
问题来了, dojo是怎么知道flickrApp.js模块的文件系统中存放的位置的呢? 答案就是dojo的路径管理机制, dojo会根据你传入
dojo.provide()
的字符串来定位该模块的位置,基准点是dojo.js的上一级目录, 比如dojo.js在
http://localhost:8888/dojo/dojo.js,所以dojo会在
http://localhost:8888/这个目录级别(dojo.js的上一级)来定位所有的模块。 为了说明这个问题, 我们现在来再一次改变例子的文件结构,使其看起来
更加具有组织性,如下:
此时,所有的应用相关的代码都在flickrApp这个目录(名字空间)下,在这个目录下,我们可以更进一步将该应用切分成不同的模块。第一个模块就是data.js模块,包含获取
Flickr数据的逻辑功能,以及跨域,返回数据等等功能。基于这个改变,我们需要在data.js里面加入
dojo.provide()语句来告诉他新的目录结构的改变,如下(
data.js
):
- //below is similar to doing var flickrApp = {}; flickrApp.data = {};
- dojo.provide(”flickrApp.data “);
- // Note: do not include the .js
- flickrApp.data.getData = function(){};
就像我们之前所说的,dojo会从dojo.js(http://localhost:8888/dojo/dojo.js
)的上一级目录来开始定位各个模块,所以这里dojo定位我们的data.js
模块的路径为http://localhost:8888/flickrApp/data.js。此时,我们的HTML代码也要做相应的改动:
<html lang=”en”>
<head>
<meta charset=”utf-8″ />
<title>Dojo</title>
</head>
<body>
<script src=”/dojo/dojo.js”></script>
<script>
dojo.require(”dojo.io.script”);
dojo.require(”flickrApp.data “);
</script>
</body>
</html>
好了,到此为止,我们来想一想,这样做真的有必要吗,我们为什么不能不要借助这种模块系统,而仅仅是把应用程序所有的逻辑功能都放在一个javascript文件中呢? 当然可以。但是dojo实现模块系统的目的在于更好更方便的管理代码,也便于用工具压缩优化代码。
接下来我们讨论一下最重要的部分:依赖管理.
模块可以包含对其他模块的引用,即在模块中可以require()其他的模块, dojo会帮你管理这些模块,让我们回到我们HTML页面:
<html lang=”en”>
<head>
<meta charset=”utf-8″ />
<title>Dojo</title>
</head>
<body>
<script src=”/dojo/dojo.js”></script>
<script>
dojo.require(”dojo.io.script”);
dojo.require(”flickrApp.data”);
</script>
</body>
</html>
我们可以看到,这里我们会在HTML页面上require 这个dojo.io.script.js模块, 事实上我们可以把这个
require()语句放到
data.js模块里面,其实这里
data.js模块是依赖于
dojo.io.script.js模块的,dojo会管理这个依赖关系,所以此时
data.js模块如下:
- dojo.provide(”flickrApp.data”);
- dojo.require(”dojo.io.script”);
- // Note: dojo.require() should be used after dojo.provide()
- flickrApp.data.getData = function(){};
此时,我们的HTML页面就只需要包含一个 require()
语句 (data.js模块)
.
<html lang=”en”>
<head>
<meta charset=”utf-8″ />
<title>Dojo</title>
</head>
<body>
<script src=”/dojo/dojo.js”></script>
<script>
dojo.require(”flickrApp.data”);
</script>
</body>
</html>
dojo会管理这些依赖关系,确保data.js依赖于
dojo.io.script.js。
更有甚者,依赖管理还需要一个响应通知,即当所有依赖的模块都被加载完成后的一个响应通知。这件事情可以用dojo.ready()这个函数来实现,
dojo.ready()将会注册一个函数,这个函数会在所有的DOM节点加载完成,并且所有模块及其的依赖模块都加载和解析完成时 被调用。用法如下:
<html lang=”en”>
<head>
<meta charset=”utf-8″ />
<title>Dojo</title>
</head>
<body>
<script src=”/dojo/dojo.js”></script>
<script>
dojo.require(”flickrApp.data”);
dojo.ready(function(){
// Note that dojo.ready() is a shortcut for dojo.addOnLoad() added in Dojo 1.4
// Run code from data.js and all its dependencies safely
});
</script>
</body>
</html>
dojo.ready()
可以用在任何时间,任何地方,甚至是dojo.ready()的callback方法里面,比如
:
- dojo.require(”some.module”);
- dojo.ready(function(){
- //run code from some.module.js and all its dependencies safely
- dojo.require(’some.other.module’);
- dojo.ready(function(){
- //run code from some.other.module.js and all its dependencies safely
- });
- });
就像前面提到的,当用到dojo的 require()时,dojo会从dojo.js的上一级目录开始查找,比如
require('some.other.module')会从
some/other/module.js开始查找:
其实dojo也提供了我们定义dojo的默认查找路径的方式,我们再更新一下我们应用程序的结构,如下:
可以看到,我们的模块 - some.other.module.js已经在dojo默认的模块查找路径之外了,我们要告诉dojo这个结构的变化就要用到
dojo.registerModulePath():
<html lang=”en”>
<head>
<meta charset=”utf-8″ />
<title>Dojo</title>
</head>
<body>
<script src=”/js/dojo1.4.1/dojo.js”></script>
<script>
dojo.registerModulePath(”some”, “../../some/”);
dojo.require(”some.other.module”);
</script>
</body>
</html>
通过dojo.registerModulePath("some", "../../some/")
语句,dojo便知道这个用户自定义的模块的位置,这里,我们告诉dojo我们的自定义模块some是在dojo.js的上两级(../../some
),这个时候,dojo便知道了如何去解析这个名字空间(some.other.module
)并加载some.other.module.js文件了。此时此刻,dojo便能识别所有在“
../../some/
”路径下的自定义模块。之所以需要这样做的原因主要是安全问题,浏览器是不支持javascript访问文件系统的。 如果你对
djConfig 比较了解的话,你会发现其实这个对象也可以用来做“dojo.registerModulePath()
”的工作:
<html lang=”en”>
<head>
<meta charset=”utf-8″ />
<title>Dojo</title>
</head>
<body>
<script type=”text/javascript”>
var djConfig = {modulePaths:{”some”:”../../some/”}};
</script>
<script src=”/dojo/dojo1.4.1/dojo.js”></script>
<script>
dojo.require(”some.other.module”);
</script>
</body>
</html>
其实dojo关于模块系统的内容还有很多,这里我们主要是基于本地的dojo,其实dojo还可以以跨域的方式加载(从AOL或者Google CDN),所以模块系统也会去支持这种特性。模块系统的底层实现是基于XHR去请求模块内容的,这些在你用dojo的CDN版本是会改变,这时模块系统会转换到跨域的方式(基于script元素)。
Dojo之外
其实这些模块系统的想法也可以在没有dojo的情况下使用。 YUI3.0也有一个类似的实现,同样,也有一些针对模块系统的想法而专门实现的独立的控件库,其中之一就是RequireJS ,他是基于dojo实现的。有兴趣不妨下载下来研究一下。
dojo.require()的相关理解的更多相关文章
- 理解dojo.require机制
转自:http://blog.csdn.net/dojotoolkit/article/details/5935844 Dojo 提供了一个非常强大的javascript控件库. 在使用dojo之前, ...
- C++ 模板特化以及Typelist的相关理解
近日,在学习的过程中第一次接触到了Typelist的相关内容,比如Loki库有一本Modern C++ design的一本书,大概JD搜了一波没有译本,英文版600多R,瞬间从价值上看到了这本书的价值 ...
- iOS中respondsToSelector与conformsToProtocol的相关理解和使用
respondsToSelector相关的方法 : -(BOOL) isKindOfClass: classObj 用来判断是否是某个类或其子类的实例 -(BOOL) isMemberOfClass: ...
- 对于EL表达式和ONGL表达式区别的相关理解
java程序跑起来之后,会有一个内存空间分配出来,存入用到的值,这个值的周围就是上下文空间,而九大内置对象等,都在这个值的周围放着,像这样: el 就只能获取value stack 周围 的数据,va ...
- JavaScript 正则表达式相关理解
1.使用正则的test.exec方法而且带有g属性进行连续匹配的时候, 如果每次匹配之前 lastIndex属性没有清零. <script> var str='123qweQWE125|2 ...
- iOS之即时通讯相关理解
Socket: 1>Socket又称"套接字" 2>网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. 3>应用程序通常通 ...
- 【Oracle】-【体系结构】-【DBWR】-DBWR进程相关理解
对DBWR的一些理解 首先从名称上,DBWR全称是Database Writer Process,属于Oracle后台进程的一种,有的地方也叫DBWn,我想这里是出于DBWR进程个数的原因,DBWR进 ...
- 对js原型及构造函数的相关理解
一.js中的原型创建(声明)一个函数,浏览器在内存中会创建一个对象.每个函数都默认会有一个属性prototype指向了这个对象,就是说prototype的属性的值就是这个对象.此对象就是该函数的原型对 ...
- 神经网络中Epoch、Iteration、Batchsize相关理解
batch 深度学习的优化算法,说白了就是梯度下降.每次的参数更新有两种方式. 第一种,遍历全部数据集算一次损失函数,然后算函数对各个参数的梯度,更新梯度.这种方法每更新一次参数都要把数据集里的所有样 ...
随机推荐
- 网站初步收工---www.dkill.net
今天10.30左右备案核审成功了,然后一天都在忙部署和一些其他的东西,中途也写了很多文档,遇到很多问题,直接琢磨了N久,暂时发了这么多教程,明天揭露阿里云的各种坑(先用winServer服务器,有时间 ...
- SQL Server中CTE的另一种递归方式-从底层向上递归
SQL Server中的公共表表达式(Common Table Expression,CTE)提供了一种便利的方式使得我们进行递归查询.所谓递归查询方便对某个表进行不断的递归从而更加容易的获得 ...
- SQL Server 无法生成 FRunCM 线程。请查看 SQL Server 错误日志和 Windows 事件日志
1.IP地址配置不正确: 打开 Microsoft SQL Server 2005配置工具下的SQL Server Configuration Manager,选择MSSQLSERVER协议, 然后双 ...
- OpenCascade B-Spline Basis Function
OpenCascade B-Spline Basis Function eryar@163.com Abstract. B-splines are quite a bit more flexible ...
- 【开源】OSharp3.3框架解说系列:开发计划与进度
OSharp是什么? OSharp是个快速开发框架,但不是一个大而全的包罗万象的框架,严格的说,OSharp中什么都没有实现.与其他大而全的框架最大的不同点,就是OSharp只做抽象封装,不做实现.依 ...
- Percona博客学习总结
1. Upgrading to MySQL 5.7, focusing on temporal types 在MySQL 5.6.4中,对TIME, TIMESTAMP and DATETIME三种时 ...
- 让你的Mac支持NTFS
前段时间换成Mac电脑之后,发现有一点不爽,不能在Mac下写入NTFS格式的磁盘,所以就去研究了一下. 解决方法有如下三种. 第一种,直接使用第三方软件,如Paragon NTFS for MAC,T ...
- C# 将excel表格嵌入到Word中
C# 将excel表格嵌入到Word中 继续开扒,今天要实现的是使用C#将excel表格嵌入到Word中这个功能,将word表格导入到excel中我已经写过了,如有需要可参考我之前的文章,在开始前还有 ...
- C#基于两种需求向图片添加水印
使用场景 1.也就是大家经常用的,一般是图片的4个角落,基于横纵坐标来添加. 2.在图片内基于固定位置,文字始终居中.刚开始我基于第一种场景来根据水印汉字的长度来计算坐标,后来发现方法始终不可靠.现在 ...
- SQLServer学习笔记系列11
一.写在前面的话 身体是革命的本钱,这句放在嘴边常说的话,还是拿出来一起共勉,提醒一起奋斗的同僚们,保证睡眠,注意身体!偶尔加个班,也许不曾感觉到身体发出的讯号,长期晚睡真心扛不住!自己也制定计划,敦 ...