Node.js快速入门

一、概述

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. Node.js' package ecosystem, npm, is the largest ecosystem of open source libraries in the world.

Node.js是一个基于Google Chrome的V8引擎的JavaScript运行环境,它允许使用JavaScript语言编写服务器端代码。Node.js具有事件驱动和I/O非阻塞两大特点,轻量而高效。

官网地址

二、安装与运行

从官网下载最新版本的Node.js,直接安装。安装时选择全部组件,并添加到环境变量Path中。

运行命令:node -v查看是否安装成功。

运行命令:node进入到node.js的交互环境,可以输入任意JavaScript语句,并查看运行结果。

运行命令:node <*.js>直接执行js文件里的内容。

运行命令:node --use_strict <*.js>为js文件开启严格模式。

安装Node.js的时候,会自动安装包管理工具npm。

运行命令:npm -v查看npm的版本。

命令行模式会一次性执行js文件,中间没有交互;交互模式则是每一行单独执行,可以进行交互。

如果不想使用集成的IDE,可以使用VS Code编辑器进行Node.js的开发和调试。具体操作和配置可以参照VS Code的官网教程。

VS Code官网地址

Node.js Applications with VS Code

三、模块

在Node.js环境中,一个js文件就称之为一个模块。使用模块提高了代码的可维护性以及可重用性,还避免了函数名和变量名冲突。

当在模块中定义一个对象(对象、函数、数组等)时,可以输出这个对象以供其他模块使用:

module.exports = object_name;

其他模块要想使用这个对象,可以在模块中引入该对象:

var variable_name = require('/path/to/the/module/module_name');

Tips:如果不指定路径,Node会按照内置模块、全局模块、当前模块的顺序进行查找。

1、基本模块

在浏览器中,JavaScript有一个全局对象window;而在Node.js环境中,也有一个全局对象global。由于JavaScript代码既能在浏览器执行,也能在Node环境下执行,可以通过全局对象名称来判断JavaScript代码是在哪个环境下执行的。

process也是Node.js提供的一个对象,表示当前Node.js进程,进程本身的事件由process来处理。

2、常用内置模块

fs模块是文件系统模块,负责文件的读写操作,提供了同步和异步两种方法。大部分作为服务端的代码,必须使用异步代码。但是在服务器启动时读取配置文件,或结束时写入状态等操作,因为这些代码只执行一次,所以可以使用同步方法。

读文本文件:

var fs = require('fs');
fs.readFile('input.txt', 'utf-8', function (err, data) {
  if (err) {
    console.log(err);
  } else {
    console.log(data);
  }
});

其中,readFile函数的第一个参数是文件名,第二个参数是文件编码,第三个参数是一个回调函数。回调函数的第一个参数代表错误信息,第二个参数代表返回结果。

读二进制文件:

var fs = require('fs');
fs.readFile('input.png', function (err, data) {
  if (err) {
    console.log(err);
  } else {
    console.log(data);
    console.log(data.length + ' bytes');
  }
});

其中,不需要文件编码,并且回调函数的data参数将返回一个Buffer对象。Buffer对象是一个包含零个或任意个字节的数组。

写文件:

var fs = require('fs');
var data = 'Hello world';
fs.writeFile('output.txt', data, function (err) {
  if (err) {
    console.log(err);
  } else {
    console.log('success');
  }
});

其中,writeFile函数的第一个参数是文件名,第二个参数是要写入的数据,第三个参数是回调函数。

读取文件的相关信息:

fs.stat('input.txt', function (err, stat) {
  ...
});

stream是一个只能在服务端使用的模块,用来支持流数据结构,流中的数据是有序的。流是一个对象,使用时只需关注流的事件即可。data事件表示流的数据可以读取,end事件表示流没有数据可以读取,error事件表示出现错误。

读文件:

var fs = require('fs');
var rs = fs.createReadStream('input.txt', 'utf-8');
rs.on('data', function (chunk) {
  console.log('DATA:');
  console.log(chunk);
});
rs.on('end', function () {
  console.log('END');
});
rs.on('error', function (err) {
  console.log('ERROR: ' + err);
});

写文件:

var fs = require('fs');
var ws1 = fs.createWriteStream('output1.txt', 'utf-8');
ws1.write('使用Stream写入文本数据...\n');
ws1.write('END.');
ws1.end();

var ws2 = fs.createWriteStream('output2.txt');
ws2.write(new Buffer('使用Stream写入二进制数据...\n', 'utf-8'));
ws2.write(new Buffer('END.', 'utf-8'));
ws2.end();

可以使用管道操作pipe将读取流和写入流串联起来:

var fs = require('fs');
var rs = fs.createReadStream('input.txt');
var ws = fs.createWriteStream('output.txt');
rs.pipe(ws);

默认情况下,当读取流的数据读取完毕,会触发end事件,并自动关闭写入流。如果不想关闭,需要传递额外的参数。

readable.pipe(writable, { end: false });

http模块是web应用最常用的一个模块,提供了request和response对象。request对象封装HTTP请求,调用request对象的属性和方法,可以获取HTTP请求的所有信息;response对象封装HTTP响应,调用response对象的方法,可以把HTTP响应返回给浏览器。

var http = require('http');
var server = http.createServer(function (request, response) {
  // 获取HTTP请求的method和url
  console.log(request.method + ':' + request.url);
  // 将HTTP响应的内容写入response
  response.writeHead(200, {'Content-Type': 'text/html'});
  response.end('<h1>Hello world!</h1>');
});
// 监听8080端口
server.listen(8080);

url模块可以用来将URL字符串解析成一个Url对象,从而获取想要的信息。

var url = require('url');
console.log(url.parse('http://user:pass@host.com:8080/path/to/file?query=string#hash'));

path模块可以用来处理本地文件目录。

var path = require('path');
// 解析当前目录
var workDir = path.resolve('.');
// 组合完整的文件路径
var filePath = path.join(workDir, 'pub', 'index.html');

crypto模块提供通用的加密和哈希算法。

MD5哈希算法用来给任意数据一个签名,通常用一个十六进制字符串表示:

const crypto = require('crypto');
const hash = crypto.createHash('md5');
hash.update('Hello, world!');
console.log(hash.digest('hex'));

Hmac哈希算法可以利用MD5等算法,另外还需要一个密钥:

const crypto = require('crypto');
const hmac = crypto.createHmac('sha256', 'secret-key');
hmac.update('Hello, world!');
console.log(hmac.digest('hex'));

AES是一种常用的对称加密算法,加密与解密使用同一个密钥。crypto模块提供了AES支持,但需要自行封装。DiffieHellman算法是一种密钥交换协议,可以让双方自行协商一个密钥。crypto模块还可以处理数字证书。

四、Web开发

使用Node.js开发Web服务器端,有几点好处:

  • 前后端统一使用JavaScript,不需要切换语言
  • 异步处理大大提高了运行速度

针对Node.js,出现了很多后端相关的Web框架、ORM框架、模板引擎、测试框架、构建工具等。

1、Web框架Express/koa

Express是第一代最流行的Web服务端框架,它对Node.js的http进行了封装。虽然Express的API非常简单,但是由于是基于ES5,要实现异步,只能使用回调。如果异步嵌套层次过多,代码很难理解。

var express = require('express');
var app = express();
app.get('/', function (req, res) {
  res.send('Hello World!');
});
app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});

koa1基于ES6,使用generator实现异步。虽然使用generator在写法上比回调简单,但其本意并不是用于异步。真正设计用来实现异步的是Promise,但Promise的写法过于复杂。

var koa = require('koa');
var app = koa();
app.use('/test', function *() {
  yield doReadFile1();
  var data = yield doReadFile2();
  this.body = data;
});
app.listen(3000);

koa2基于ES7,使用Promise和关键字async配合实现异步,同时兼容generator的写法。

app.use(async (ctx, next) => {
  await next();
  var data = await doReadFile();
  ctx.response.type = 'text/plain';
  ctx.response.body = data;
});

2、ORM框架Sequelize

ORM技术是将关系型数据库的表结构映射到对象上,Sequelize返回Promise对象,可以更好地进行异步处理。

ES6:

Pet.findAll()
 .then(function (pets) {
   for (let pet in pets) {
     console.log(`${pet.id}: ${pet.name}`);
   }
 }).catch(function (err) {
   // error
 });

ES7:

(async () => {
  var pets = await Pet.findAll();
})();

要想使用Sequelize操作数据库,首先需要创建一个Sequelize实例。然后定义数据模型Model,使用Sequelize映射数据库表。这样就可以调用实例的相应方法来对数据库进行操作。

Sequelize操作数据库的一般步骤:

  • 通过Model对象的findAll()方法获取实例
  • 如果要更新实例,先对实例属性进行赋值,然后调用save()方法
  • 如果要删除实例,直接调用destroy()方法

3、模板引擎Jade/Pug

Node.js默认使用Jade作为模板引擎(现改名为Pug)。Jade是Node.js的一个模块,jade文件可以被预编译为.js文件,也可以被编译为目标html代码。

主页

4、测试框架Mocha

Mocha是JavaScript的单元测试框架,既可以在浏览器环境运行,也可以在Node.js的环境运行。

特点:

  • 既可以测试简单的JavaScript函数,又可以测试异步代码
  • 既可以自动运行所有测试,也可以只运行特定的测试
  • 可以支持before、after、beforeEach和afterEach来编写初始化代码

5、构建工具Webpack

6、WebSocket协议

WebSocket利用HTTP协议建立连接,在浏览器和服务器之间建立双向通信的通道,服务器可以主动向浏览器发送消息,而不需要通过浏览器发送请求。

首先,WebSocket连接必须由浏览器发起,因为请求协议是一个标准的HTTP请求。

GET ws://localhost:3000/ws/chat HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Origin: http://localhost:3000
Sec-WebSocket-Key: client-random-string
Sec-WebSocket-Version: 13

与普通HTTP请求的区别:

  • GET请求的地址以ws://开头
  • 请求头Upgrade: websocketConnection: Upgrade表示连接将被转换为WebSocket连接
  • Sec-WebSocket-Key用于标识这个连接
  • Sec-WebSocket-Version指定WebSocket的协议版本

然后,如果服务器接受请求,会返回响应:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: server-random-string

其中,响应码101表示将切换协议,切换后的协议通过Upgrade来指定。

在Node.js中,最常用的WebSocket模块是ws。创建一个WebSocket的服务器实例:

const WebSocket = require('ws');
const WebSocketServer = WebSocket.Server;
const wss = new WebSocketServer({
  port: 3000
});

如果有WebSocket请求接入,wss对象可以响应connection事件来处理这个WebSocket。对于每个WebSocket连接,都要对它绑定某些事件方法来处理不同的事件。


参考文章:

廖雪峰:Node.js教程

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

推荐阅读更多精彩内容

  • 1. 开始使用nodejs 1.1. Hello Word 好了,让我们开始实现第一个 Node.js 程序吧。打...
    angelwgh阅读 2,292评论 1 8
  • Node.js是目前非常火热的技术,但是它的诞生经历却很奇特。 众所周知,在Netscape设计出JavaScri...
    Myselfyan阅读 4,062评论 2 58
  • Node.js是目前非常火热的技术,但是它的诞生经历却很奇特。 众所周知,在Netscape设计出JavaScri...
    w_zhuan阅读 3,607评论 2 41
  • 古风版的【爱请转移】 若有幸他也听闻 我依然在等
    397f2d7b7d0b阅读 251评论 1 0
  • 大连北站开往丹东站,途径庄河北站。 金州站,广宁寺站,登沙河站,皮口站····· 我的天每一站都停! 如果是个电影...
    郭永伟阅读 193评论 0 0