您的位置:首页 > Web前端 > JavaScript

基于JVM的服务端javascript平台Ringo.js入门(三):模块以及包实现

2013-10-04 20:38 871 查看
  这次内容是我比较感兴趣的部分,即所谓模块化支撑。通过他们,Ringo提供给了相当好的功能解偶机制(node.js的npm也源于node.js中类似机制的实现)。我的计划是,利用这个机制在javaweb上仿制wordpress的plugin插件功能。
  在研究过程中,主要关注package以及module在require时的查找路径方式。
  ringo的模块与包的实现与node.js以及vertx实现同源,common-js标准。其module依赖cj-module1.1标准,其package依赖cj-package1.0标准。
  
  这里偷个懒,在网上看到有个同学已经把官网的说明翻译过来了。引用其中的大部分内容:http://www.skyatlas.net/?s=ringojs

Modules in Ringo

Ringo实现了CommonJS Modules1.1规范,在Javascript世界中,存在多个可用Module patterns,但是在Ringo的世界里,我们只用这个:

每一个文件就是一个模块,不需要特别的语法申明
任何function或者其他属性,只要你在module(文件)中,attatch到exports对象上,他们就被导出(让外部可见),成为这个模块的导出属性
require(‘foobar’)会返回一个拥有模块所有exposed属性的对象,代表foobar模块
剖析Module

In Ringo,每一个javascript文件都被当做是一个module,Ringo提供导入、导出的实现。

一个简单的例子会让事情变得更明白。下面我们实现一个foobar.js模块(module),我们希望这个模块提供add方法,而不是其内部私有方法adder:

// foobar.js
varadder = function(a, b) {
return a + b;
};
exports.add = function(a, b) {
return adder(a, b );
};

这样,我们就完成了一个module的实现,我们现在可以在ringo环境中,通过require引入这个模块,然后调用这个模块对外开放的add方法(以下在Ringo命令行中执行, >>是Ringo命令行提示符):

>> varfoobar =  require(‘foobar’);
>> foobar.add(3, 4);
7


而模块(module)中的私有(没有export)的方法,我们不能调用:

>> foobar.adder(2, 2);
TypeError: Cannot find function adder in object [object Object].


Ringo为每一个模块(module)对象提供了一个module对象,这个module对象包含如下属性:

id – 模块的标识id
path-模块的文件路劲
uri-模块的URL
exports-assigning to this property allows modules to replace the default exports object(如何使用??)
模块在私有区域执行,在模块中,除了显式定义为exported的对象属性,其他都是私有不被外部环境或者其他模块可见的——这个解决了JavaScript编程中常见的统一Namespace中,属性混乱、冲突的问题。

Module IDs: module文件名称,去除.js扩展名,相对ID,绝对ID——类似于相对路径、绝对路径的概念。

Module Path: 一些列的路径位置(多个!),Ringo会在其中寻在module,可以通过如下途径设置:

RINGO_MODULE_PATH 环境变量
ringo.modulepath Java System Property
-m 或者 –modules ——ringo的命令行启动参数
使用module-path servlet 初始化参数——JsgiServlet
在Ringo环境中,变更require.paths属性(Array-Like)
从Ringo 0.8版本开始,默认的module路劲(module path)包含安装目录下的modules和packages文件夹。Ringo 0.8也可以不用配置的从Java Classpath中装载modules。——0.8之前的版本?不提了。

Packages

Package是组合几个相关的模块(module)以及相关资源的单位。

Package是包含package.json(Package描述文件)的文件夹。下面的package.json能够被Ringo的模块装载机制(Module Loader)识别:

{
“main”: “/lib/main.js”
}


如 果我们在使用require(或者其他通过module id引入模块的机制)引入模块时,module id指向自定义的包目录,并且package.json文件中定义了main属性,Ringo将尝试装载制定资源。main的属性中的文件路劲必须是 针对package root的相对路径。



如上mypkg是一个存在package.json的包目录。

如果module id指向一个目录,目录中不存在package.json(不是Package),或者存在package.json但是其中没有定义main属性,Ring将尝试装载该目录下的index.js文件。

如果module id的一部分为package目录(存在package.json以及main属性。),Ringo将剩余的module id部分在Package 目录的lib目录中解析、寻找(就是说引用路径可以省略实例目录lib。这种方式可能是方便package内部模块引用而出现的。);在package.json文件中可以定义directories.lib属性,覆盖默认的lib文件夹:

{
“directories”: {
“lib”: “lib”
}
}




Ringo也可以通过ringo-admin工具,进行简单的package管理工作。

 

Caching & Reloading

每一个模块(module)在第一次装载后会被缓存(caching),Ringo根据module id决定一个模块是第一次装载,还是可以直接从缓存中装载;避免模块被装载超过一次,——但是在一些特定环境下,模块仍然可能被重复装载。

默 认情况下,Ringo 模块装载机制会在模块被required(这事嘛意思? require调用,还是require之后,每一次针对模块导出方法的调用??——经不严格测试,应该是做require调用时)时,自动检查此模块以 及其依赖的模块是否被修改,被修改了的模块会被重新装载。

以产品模式运行ringo可以避免模块的修改检查。 -p –production 或者在servlet环境中配置。

 

Ringo 模块扩展

CommonJS 模块管理规范设计的比较简洁,Ringo在此基础上,做了一些精巧、细微的扩展——这些扩展主要是针对export、import功能。对于“标准、规 范”的随意扩展,会导致将来代码不能迁移,还好Ringo提供了工具,可以将这些代码转换为pure CommonJS规范代码。

include就是Ringo提供的一个扩展,其用户类似于require。但是include相当于把模块代码直接copy到本地,而不是仅仅引入模块中export的属性。

在Ringo中,我们可以结合Javascript 1.8的destructuring assignment新特性,进一步增强原有的require功能:

var{foo, bar} = require(“some/module”);

在模块中,使用:

export(“foo”, “bar”, “baz”);

Destructuring Assignment是个挺有意思的新功能,后续在Ringo环境中,我们会尝试去学习使用它。(wfeng007:比较高级的javascript语言版本才提供这个特性。)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息