我们在上一节中了解了什么是node以及简单的node安装和事件式编程。呵呵。。。今天内容是
什么是模块?
什么是包?
如果我写好包了怎么发布出去给别人用?
我写好js脚本后怎么找问题,(怎么调试问题)
怎么实现远程调试?
最后一个就是调试有没有其他的现成的工具可供我们使用
最厚的问题我就在这里答了吧,因为我也没用IDE调试的,在这里就不细说了,因为还得上传老多IDE的使用图片感觉挺麻烦就不再累赘的描述了,我就在这里简单的说下了
当然调试js的IDE也是有的比如eclipse添加chrome Developer插件 插件地址http://chromedevtools.googlecode.com/svn/update/dev/
我希望你带着这几个问题去看我这篇博客这样就很容易接受这里所讲的内容了
五.模块和包
Node.js 提供了 require 函数来调用其他模块,而且模块都是基于
文件的,机制十分简单。Node.js 的模块和包机制的实现参照了 CommonJS的标准,但并未完全遵循。
1什么是模块
模块是 Node.js 应用程序的基本组成部分,文件和模块是一一对应的。换言之,一个
Node.js 文件就是一个模块,这个文件可能是 JavaScript 代码、 JSON 或者编译过的 C/C++ 扩展。
在前面章节的例子中,我们曾经用到了 var http =require(‘http‘), 其中 http
是 Node.js 的一个核心模块,其内部是用 C++ 实现的,外部用 JavaScript封装。我们通过
require函数获取了这个模块,然后才能使用其中的对象。
2块创建及加载模块
让我们以一个例子来了解模块。创建一个 module.js 的文件,内容是:
//module.js var name; exports.setName = function(thyName) { name = thyName; }; exports.sayHello = function() { console.log('Hello ' + name); }; //在同一目录下创建 getmodule.js,内容是: //getmodule.js var myModule = require('./module'); myModule.setName('BYVoid'); myModule.sayHello()
单次加载
上面这个例子有点类似于创建一个对象,但实际上和对象又有本质的区别,因为
require不会重复加载模块,也就是说无论调用多少次 require, 获得的模块都是同一个。
我们在 getmodule.js 的基础上稍作修改:
//loadmodule.js var hello1 = require('./module'); hello1.setName('BYVoid'); var hello2 = require('./module'); hello2.setName('BYVoid 2'); hello1.sayHello();
运行后发现输出结果是 Hello BYVoid 2,这是因为变量 hello1 和 hello2 指向的是
同一个实例,因此 hello1.setName 的结果被 hello2.setName 覆盖,最终输出结果是
由后者决定的。
覆盖exports
有时候我们只是想把一个对象封装到模块中,例如:
//singleobject.js function Hello() { var name; this.setName = function (thyName) { name = thyName; }; this.sayHello = function() { console.log('Hello ' + name); }; }; exports.Hello = Hello;
此时我们在其他文件中需要通过 require(‘./singleobject‘).Hello来获取
Hello 对象,这略显冗余,可以用下面方法稍微简化:
//hello.js function Hello() { var name; this.setName = function(thyName) { name = thyName; }; this.sayHello = function() { console.log('Hello ' + name); }; }; module.exports = Hello; 这样就可以直接获得这个对象了: //gethello.js var Hello = require('./hello'); hello = new Hello(); hello.setName('BYVoid'); hello.sayHello();
3创建包
包是在模块基础上更深一步的抽象, Node.js 的包类似于 C/C++ 的函数库或者 Java/.Net
的类库。它将某个独立的功能封装起来,用于发布、更新、依赖管理和版本控制。 Node.js 根
据 CommonJS 规范实现了包机制,开发了 npm来解决包的发布和获取需求。
Node.js 的包是一个目录,其中包含一个 JSON 格式的包说明文件 package.json。严格符
合 CommonJS 规范的包应该具备以下特征:
q package.json 必须在包的顶层目录下;
q 二进制文件应该在 bin 目录下;
q JavaScript 代码应该在 lib 目录下;
q 文档应该在 doc 目录下;
q 单元测试应该在 test 目录下。
Node.js 对包的要求并没有这么严格,只要顶层目录下有 package.json,并符合一些规范即可。当然为了提高兼容性,我们还是建议你在制作包的时候,严格遵守 CommonJS
作为文件夹的模块
模块与文件是一一对应的。文件不仅可以是 JavaScript 代码或二进制代码,还可以是一
个文件夹。最简单的包,就是一个作为文件夹的模块。下面我们来看一个例子,建立一个叫做 somepackage的文件夹,在其中创建 index.js,内容如下:
//somepackage/index.js exports.hello = function() { console.log('Hello.'); }; //然后在 somepackage 之外建立 getpackage.js,内容如下: //getpackage.js var somePackage = require('./somepackage'); somePackage.hello();
运行 nodegetpackage.js,控制台将输出结果 Hello.。
我们使用这种方法可以把文件夹封装为一个模块,即所谓的包。包通常是一些模块的集
合,在模块的基础上提供了更高层的抽象,相当于提供了一些固定接口的函数库。通过定制
package.json,我们可以创建更复杂、更完善、更符合规范的包用于发布。
package.json
在前面例子中的 somepackage 文件夹下,我们创建一个叫做 package.json 的文件,内容如
下所示:
{
"main" : "./lib/interface.js"
}
然后将 index.js 重命名为 interface.js 并放入 lib 子文件夹下。以同样的方式再次调用这个包,依然可以正常使用。
Node.js 在调用某个包时,会首先检查包中 package.json 文件的 main 字段,将其作为
包的接口模块,如果 package.json或 main 字段不存在,会尝试寻找 index.js 或 index.node 作为包的接口。package.json 是 CommonJS 规定的用来描述包的文件,完全符合规范的 package.json 文件应该含有以下字段。
q name:包的名称,必须是唯一的,由小写英文字母、数字和下划线组成,不能包含
空格。
q description:包的简要说明。
q version:符合语义化版本识别①规范的版本字符串。
q keywords:关键字数组,通常用于搜索。
q maintainers:维护者数组,每个元素要包含 name、 email (可选)、 web (可选)
字段。
q contributors:贡献者数组,格式与maintainers相同。包的作者应该是贡献者
数组的第一个元素。
q bugs:提交bug的地址,可以是网址或者电子邮件地址。
q licenses:许可证数组,每个元素要包含 type (许可证的名称)和 url (链接到许可证文本的地址)字段。
q repositories:仓库托管地址数组,每个元素要包含 type(仓库的类型,如 git )、
url
q dependencies:包的依赖,一个关联数组,由包名称和版本号组成。
下面是一个完全符合 CommonJS规范的 package.json 示例:
{ "name": "mypackage", "description": "Sample package for CommonJS. This packagedemonstrates the required elements of a CommonJS package.", "version": "0.7.0", "keywords": [ "package", "example" ], "maintainers": [ { "name": "Bill Smith", "email": "[email protected]", } ], "contributors": [ { "name": "BYVoid", "web": "http://www.byvoid.com/" } ], "bugs": { "mail": "[email protected]", "web": "http://www.example.com/bugs" }, "licenses": [ { "type": "GPLv2", "url": "http://www.example.org/licenses/gpl.html" } ], "repositories": [ { "type": "git", "url": "http://github.com/BYVoid/mypackage.git" } ], "dependencies": { "webkit": "1.2", "ssl": { "gnutls": ["1.0", "2.0"], "openssl": "0.9.8" } } }
4.包管理器
Node.js包管理器,即npm是 Node.js 官方提供的包管理工具,它已经成了 Node.js 包的标准发布平台,用于 Node.js 包的发布、传播、依赖控制。 npm 提供了命令行工具,使你可以方便地下载、安装、升级、删除包,也可以让你作为开发者发布并维护包
获取一个包
Node.js包管理器,即npm是 Node.js 官方提供的包管理工具①,它已经成了 Node.js包的标准发布平台,用于 Node.js包的发布、传播、依赖控制。 npm 提供了命令行工具,使你可以方便地下载、安装、升级、删除包,也可以让你作为开发者发布并维护包。
1. 获取一个包
使用 npm 安装包的命令格式为:
npm [install/i] [package_name]
例如你要安装 express,可以在命令行运行:
$ npm install express
或者:
$ npm i express
随后你会看到以下安装信息:
[email protected]_modules\express
├──[email protected]
├──[email protected]
├──[email protected]
├──[email protected]
├──[email protected]
├──[email protected]
├──[email protected]
├──[email protected]
├──[email protected]
├──[email protected]
├──[email protected]
├──[email protected]
├──[email protected]
├──[email protected]
├──[email protected]
├──[email protected]
├──[email protected]
├──[email protected]
├──[email protected]
├──[email protected] ([email protected])
├──[email protected] ([email protected])
├──[email protected] ([email protected], [email protected])
├──[email protected] ([email protected], [email protected], [email protected], [email protected],[email protected])
├──[email protected] ([email protected], [email protected])
├──[email protected] ([email protected], [email protected])
└──[email protected] ([email protected], [email protected])
此时 express 就安装成功了,并且放置在当前目录的 node_modules子目录下。 npm 在获取 express 的时候还将自动解析其依赖,并获取其他包的支持。
本地模式和全局模式
npm在默认情况下会从http://npmjs.org搜索或下载包,将包安装到当前目录的node_modules、子目录下。
在使用 npm 安装包的时候,有两种模式:本地模式和全局模式。默认情况下我们使用 npm nstall命令就是采用本地模式,即把包安装到当前目录的 node_modules 子目录下。Node.js的 require 在加载模块时会尝试搜寻 node_modules子目录,因此使用 npm 本地模式安装的包可以直接被引用。
为什么要使用全局模式呢?多数时候并不是因为许多程序都有可能用到它,为了减少多
重副本而使用全局模式,而是因为本地模式不会注册 PATH 环境变量。举例说明,我们安装supervisor是为了在命令行中运行它,譬如直接运行 supervisor script.js,这时就需要在 PATH环境变量中注册 supervisor。 npm 本地模式仅仅是把包安装到 node_modules 子目录下,其中的 bin 目录没有包含在 PATH 环境变量中,不能直接在命令行中调用。而当我们使用全局模式安装时, npm 会将包安装到系统目录, 譬如 /usr/local/lib/node_modules/,
同时 package.json 文件中 bin 字段包含的文件会被链接到 /usr/local/bin/。 /usr/local/bin/ 是在PATH 环境变量中默认定义的,因此就可以直接在命令行中运行 supervisorscript.js
总而言之,当我们要把某个包作为工程运行时的一部分时,通过本地模式获取,如果要
在命令行下使用,则使用全局模式安装
创建全局连接
如果你是个较真的人,非得要引用安装在全局下的模块的话,那要怎么办呀!不可我再从全局复制一份到本地吧!!这样做少的情况下可以如果多的情况下会让你恶心死。。。
值得庆幸的是npm为我们提过了一个命令,npm link,这个命令会在我们本地node_modules下创建一个引用全局的一个快捷连接符号噢噢,这样你就像引用本地模块式的require了是不是很爽啊!!!!!!
噹噹噹噹噹。。。。。。。。我们现在如果自己写了一个包我想让别人也用那就需要发布包咯噢噢,那要怎么发布包呢!!!!!
包的发布
首先我们要创建一个自己的包,nodejs都按commonjs标准来了那我们也不例外,我们首先创建一个package.json文件,如果你嫌手动创建麻烦,不要紧npm为我们出了一个命令叫npminit,这样我们在命令行内输入npm init,然后按照提示一步一步把版本号,包名称,写好最后会生成一个叫符合标准的package.json噢,然后创建一个lib文件夹 里边放一个index.js写上一句express.say=function(){console.log(“我要发布包了”); 这样我们手动创建的包就好了是不是很简单啊
然后我们就开始发布咯!在发布之前我们要获得一个帐号用于今后维护自己的包,使用npmadduser 根据提示输入用户名密码邮箱,等待帐号完成,完成后可以使用npmwhoami 测试是否已经取得帐号了。
接下来就可以在 package.json 所在目录下运行 npm publish稍等片刻就可以完成发布了。访问 http://search.npmjs.org/就可以找到自己刚刚发布的包了。如果你的包将来有更新,只需要在 package.json 文件中修改 version 字段,然后重新使用 npm publish 命令就行了。如果你对已发布的包不满意(比如我们发布的这个毫无意义的包),可以使用 npmunpublish 命令来取消发布
六调试
用命令方式调试
开发中难免会碰到bug,所以我想看下bug的所在位置那就需要调试了,我先说下nodejs内置的调试工具,当然也是基于命令行调试噢噢
前提是你新建一个自己的js脚本,在控制台输入node debug debug.js(debug.js是我要调试的脚本)将会打开了node.js的调试终端我们可以写一些命令来进入单步跟踪调试。
run 执行脚本,在第一行暂停
restart 重新执行脚本
cont, c 继续执行,直到遇到下一个断点
next, n 单步执行
step, s 单步执行并进入函数
out, o 从函数中步出
setBreakpoint(), sb() 在当前行设置断点
setBreakpoint(‘f()’), sb(...) 在函数f的第一行设置断点
setBreakpoint(‘script.js’, 20), sb(...) 在 script.js 的第20行设置断点
clearBreakpoint, cb(...) 清除所有断点
backtrace, bt 显示当前的调用栈
list(5) 显示当前执行到的前后5行代码
watch(expr) 把表达式 expr 加入监视列表
unwatch(expr) 把表达式 expr 从监视列表移除
watchers 显示监视列表中所有的表达式和值
repl 在当前上下文打开即时求值环境
kill 终止当前执行的脚本
scripts 显示当前已加载的所有脚本
version 显示V8 的版本
你会疑问后边的一个字母是不是多余啊!!!,一点也不多于,后边的一个字母或者两个字母的是前边单词的缩写,用缩写的方式也是好使的呵呵
远程调试
V8 提供的调试功能是基于 TCP 协议的,因此 Node.js 可以轻松地实现远程调试。在命
令行下使用以下两个语句之一可以打开调试服务器:
node--debug[=port] script.js
node --debug-brk[=port] script.js
node --debug 命令选项可以启动调试服务器,默认情况下调试端口是 5858,也可以
使用 --debug=1234 指定调试端口为 1234。使用 --debug 选项运行脚本时,脚本会正常执行,但不会暂停,在执行过程中调试客户端可以连接到调试服务器。如果要求脚本暂停执行等待客户端连接,则应该使用 --debug-brk选项。这时调试服务器在启动后会立刻暂停执行脚本,等待调试客户端连接。
node --debug 命令选项可以启动调试服务器,默认情况下调试端口是 5858,也可以
使用 --debug=1234 指定调试端口为 1234。使用 --debug 选项运行脚本时,脚本会正常执行,但不会暂停,在执行过程中调试客户端可以连接到调试服务器。如果要求脚本暂停执行等待客户端连接,则应该使用 --debug-brk选项。这时调试服务器在启动后会立刻暂停执行脚本,等待调试客户端连接。
当调试服务器启动以后,可以用命令行调试工具作为调试客户端连接,例如:
//在一个终端中
$node --debug-brk debug.js
debugger listening on port 5858
//在另一个终端中
$node debug 127.0.0.1:5858
connecting... ok
debug> n
break in /home/byvoid/debug.js:2
1 var a = 1;
2 var b = ‘world‘;
3 var c = function (x) {
4 console.log(‘hello ‘ + x + a);
debug>
事实上,当使用 node debug debug.js 命令调试时,只不过是用 Node.js命令行工
具将以上两步工作自动完成而已。