(三)NodeJs快速入门

本学习笔记是根据《Node.js开发指南》一书进行学习。前面的几篇是根据《深入浅出Node.js》学习,但是学习到第三四章关于异步I/O和异步编程时,就暂时先放弃了,主要因为那本书讲的有点深,更多从底层说起,对于从来没有接触过NodeJs的同学来说,学习起来有一些难度。《Node.js开发指南》这本书比较适合新手学习。当然本人也算新手。

开始用NodeJs编程

Hello World

创建hello.js编写如下代码:

conlose.log("Hello World")

打开终端,进入hello.js所在目录,执行命令:

node hello.js

console.log是我们最常用的输出指令,它和C语言中的printf的功能类似,也可以接受任意多个参数,支持%d%s变量引用。

console.log("%d", 1000)

建立HTTP服务器

Node.js将“HTTP服务器”这一层抽离,直接面向浏览器用户。

Node.js与PHP的架构

让我们创建一个HTTP服务,建立一个名为app.js的文件

// app.js
var http = require("http");

http.createServer(function(req, res){
    res.writeHead(200, {"Content-Type": "text/html"});
    res.write("<h1>Hello world!</h1>");
    res.end("<p>NodeJs</p>");
}).listen(3000);

console.log("Server start at port 3000!")

运行node app.js命令,打开浏览器访问http://127.0.0.1:3000,即可看到输出。

listen函数中创建了事件监听器,使得Node.js进程不会退出事件循环。

异步式I/O与事件式编程

NodeJs最大的特点就是异步式I/O(或者非阻塞I/O)与事件紧密结合的编程模式。控制流很大程度上要靠事件和回调函数来组织,一个逻辑要拆分为若干个单元。

阻塞与线程

回调函数

在NodeJs中如何用异步的方式读取一个文件,下面是一个例子:

// readFile.js
var fs = require("fs");

fs.readFile("server.js", "utf-8", function (err, data) {
    if(err){
        console.log("file read err!");
    }else {
        console.log(data);
    }
});
console.log("End!")

运行文件会发现,首先输出“End!”,然后才是读取文件的内容!

NodeJs也支持同步读取文件:

//readFile.js

var fs = require("fs");
var data = fs.readFileSync("server.js", "utf-8");
console.log(data);
console.log("End!");

运行文件,先输出文件内容,最后输出"End!"

异步式I/O是通过回调函数来实现的。fs.readFile接收了三个参数,第一个是文件名,第二个是编码方式,第三个是一个函数,我们称这个函数为回调函数。

NodeJs中,并不是所有的API都提供了同步和异步版本。Node.js不鼓励使用同步I/O。

事件

NodeJs所有的异步I/O操作在完成时都会发送一个事件到事件队列。事件由EventEmitter对象提供

//event.js
var EventEmitter = require("events").EventEmitter;
var event = new EventEmitter();
event.on("some_event", function(){
    console.log("some_event occured");
});
setTimeout(function(){
    event.emit("some_event");
}, 1000);

运行这段代码,1秒后控制台输出了some_event occured。其原理是event对象注册了事件some_event的一个监听器,然后我们通过setTimeout在1000毫秒以后向event对象发送事件some_event,此时会调用some_event的监听器。

NodeJs程序由事件循环开始,到事件循环结束,所有的逻辑都是事件的回调函数,所以NodeJs始终在事件循环中,程序入口就是事件循环第一个事件的回调函数。事件的回调函数在执行的过程中,可能会发出I/O请求或直接发射(emit)事件,执行完毕后再返回事件循环,事件循环会检查事件队列中有没有未处理的事件,直到程序结束。

模块和包

NodeJs提供了require函数来调用其他模块,而且模块都是基于文件的,机制十分简单。

NodeJs提供了exportsrequire两个对象,其中exports是模块公开的接口,require用于从外部获取一个模块的接口,即所获取模块的exports对象。

让我们以一个例子来了解模块。

// module.js
var name;
exports.setName = function(thyName){
    name = thyName;
}
exports.getName = function(){
    console.log("Hello " + name);
}

编写getModule.js

// getModule.js
var myModule = require("./module");
myModule.setName("Hak");
myModule.getName();

运行getModule.js会输出: Hello Hak

单次加载

上面这个例子有点类似于创建一个对象,但实际上和对象又有本质的区别,因为require不会重复加载模块,也就是说无论调用多少次require,获得的模块都是同一个。

我们在getModule.js的基础上稍作修改:

var myModule1 = require("./module");
myModule1.setName("Hak");

var myModule2 = require("./module");
myModule2.setName("Jack");

myModule1.getName();

运行后发现输出结果是: Hello Jack。这是因为myModule1 和myModule2指向的是同一个实例,前者的结果被后者覆盖。

事实上,exports本身仅仅是一个普通的空对象,即{},它专门用来声明接口,本质上是通过它为模块闭包
的内部建立了一个有限的访问接口。因为它没有任何特殊的地方,所以可以用其他东西来代替。

不可以通过对exports直接赋值代替对module.exports赋值。exports实际上只是一个和module.exports指向同一个对象的变量,它本身会在模块执行结束后释放,但module不会,因此只能通过指定module.exports来改变访问接口。

模块和包

npm是NodeJs官方提供的包管理工具。npm提供了命令行工具,使你可以方便地下载、安装、升级、删除包,也可以让你作为开发者发布并维护包。

在使用npm安装包的时候,有两种模式:本地模式和全局模式。默认情况下我们使用npm install命令就是采用本地模式,即把包安装到当前目录的node_modules子目录下。

npm还有另一种不同的安装模式被成为全局模式,使用方法为:

 npm install -g [page_name]
模式 可通过require使用 注册PATH
本地模式
全局模式

当我们要把某个包作为工程运行时的一部分时,通过本地模式获取,如果要在命令行下使用,则使用全局模式安装。

调试

命令行调试

NodeJs支持命令行下的单步调试。

// debug.js
var a = 1;
var b = 'world';
var c =function(x){
    console.log('hello' + x + a);
};
c(b);

在命令行下执行node debug debug.js,将会启动调试工具:

image.png

这样就打开了一个NodeJs的调试终端。可以用一些基本的命令进行单步跟踪调试。

命令 功能
run 执行脚本在第一行暂停
restart 重新执行脚本
cont, c 继续执行,直到遇到下一个断点
next, n 单步执行
step, s 单步执行并进入函数
kill 终止当前执行的脚本
... ...

远程调试

V8提供的调试功能是基于TCP协议的,因此Node.js可以轻松地实现远程调试。在命令行下使用以下两个语句之一可以打开调试服务器。

node --debug[=port] script.js
node --debug-brk[=port] script.js

利用工具

使用node-inspector调试NodeJs

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容