Nodejs基础学习(1)

极客学院Nodejs学习,还有菜鸟课程

Nodejs资料:https://github.com/nswbmw/N-blog

1.Nodejs解决的问题

1、Node.js 在前端开发中,主要是作为工具,比如打包工具 Webpack / Gulp 等,都是使用 Node.js 编写的

2、Node.js 并不直接解决前端问题,只是作为前端开发的工具

3、作为前端开发中的工具角色,在没有它之前, js / css 的打包,压缩,一般使用各种命令行工具,但无法做到与 js 的深度整合,例如,完全不能实现像 webpack / browserify 一样根据 js 中的 require / import 来打包文件

另外,Node.js 主要是作为一个后端语言。它可以像 PHP / Python 一样编写后端逻辑。但 JavaScript 生来就是以事件驱动的,所以它非常适合处理各种 IO(网络请求、数据库、存储操作等)。

2.npm全局安装和局部安装

可以参考文章:

https://www.cnblogs.com/linziwei/p/7786895.html
https://www.cnblogs.com/PeunZhang/p/5629329.html
https://yq.aliyun.com/articles/36217

附注:局部安装时候,命令行窗口运行位置是在项目文件夹下,node_modules文件夹所在位置。

3.Nodejs回调函数

Nodejs异步编程的直接体现就是回调,异步编程依托于回调来实现,但不能说使用了回调后程序就是异步化了。

回调函数在完成任务后就会被调用,Node 使用了大量的回调函数,Node 所有 API 都支持回调函数。

例如,我们可以一边读取文件,一边执行其他命令,在文件读取完成后,我们将文件内容作为回调函数的参数返回。这样在执行代码时就没有阻塞或等待文件 I/O 操作。这就大大提高了 Node.js 的性能,可以处理大量的并发请求。

-- 阻塞代码示例
var fs = require("fs");

var data = fs.readFileSync('input.txt');

console.log(data.toString());
console.log("程序执行结束!");

-- 非阻塞代码示例
var fs = require("fs");

fs.readFile('input.txt', function (err, data) {
    if (err) return console.error(err);
    console.log(data.toString());
});

console.log("程序执行结束!");

以上两个实例我们了解了阻塞与非阻塞调用的不同。第一个实例在文件读取完后才执行完程序。 第二个实例我们不需要等待文件读取完,这样就可以在读取文件时同时执行接下来的代码,大大提高了程序的性能。

因此,阻塞是按顺序执行的,而非阻塞是不需要按顺序的,所以如果需要处理回调函数的参数,我们就需要写在回调函数内。

同步是指一个时刻仅有一件事件在执行。

异步指一个时刻可以有多个事件同时执行。

阻塞指事件执行必须连续,一个事件从开始到结束不能有其他的事件插入执行。

非阻塞指事件可以分成小段执行,不要求从开始到结束连续执行。

4.Nodejs事件驱动编程

可以参考文章:

https://segmentfault.com/a/1190000005173218(程序调用顺序可以参考这个)
https://blog.csdn.net/sinat_25127047/article/details/54016931
https://www.cnblogs.com/lua5/archive/2011/02/01/1948760.html
https://blog.csdn.net/charlene0824/article/details/51711154
https://segmentfault.com/a/1190000004322358

同步概念:阻塞式调用,等待执行。
回调概念:回调是一个异步等效的功能。(不直接返回执行结果,而是在函数的参数中传递回调函数,在回调函数中处理返回结果。)

var test = function(name,callback){
    callback(name);
}

var callback = function(name){
    echo 'I am come from callback';
    return name;
}

test('jike',callback);

异步概念:非阻塞,通知获取结果。(非阻塞调用,将异步的代码添加到系统内核中,在系统内核中执行异步代码,主干中通过回调函数获取异步执行结果,异步代码执行过程中不影响主干中代码的运行过程。)

这里写图片描述

/**
 *
 * 文件名:answer.js,Node.js测试代码,应用代码说明异步调用思想
 */

function Person(){

    this.think = function(callback){  //  定义Person对象的think方法 异步函数
        setTimeout(function(){
            console.log('thinking~~~!');
        },5000);
    }

    this.answer = function(){         // 定义Person对象的answer方法 同步函数
        console.log('I am answering other questions');
    }
}

var person = new Person();               // new创建Person对象
person.think(function(){                 // 根据person对象调用think方法
    console.log('tinking 5 seconds, get the right answer!')
});
person.answer();    

# 打印结果
I am answering other questions
thinking~~~!
thinking 5 seconds,get the right answer!

5.Nodejs的EventEmitter

Node.js 有多个内置的事件,我们可以通过引入 events 模块,并通过实例化 EventEmitter 类来绑定和监听事件,如下实例:

// 引入events 模块
var events = require('events');
// 创建eventEmitter 对象
var eventEmitter = new events.EventEmitter();
// 绑定事件及事件的处理程序
eventEmitter.on('eventName',eventHandler);
// 通过程序触发事件
eventEmitter.emit('eventName');

实例:

// 引入 events 模块
var events = require('events');
// 创建 eventEmitter 对象
var eventEmitter = new events.EventEmitter();

// 创建事件处理程序
var connectHandler = function connected() {
   console.log('连接成功。');

   // 触发 data_received 事件 
   eventEmitter.emit('data_received');
}

// 绑定 connection 事件处理程序
eventEmitter.on('connection', connectHandler);

// 使用匿名函数绑定 data_received 事件
eventEmitter.on('data_received', function(){
   console.log('数据接收成功。');
});

// 触发 connection 事件 
eventEmitter.emit('connection');

console.log("程序执行完毕。");

# 输出结果
$ node main.js
连接成功。
数据接收成功。
程序执行完毕。

EventEmitter的每个事件由一个事件名和若干个参数组成,事件是一个字符串,通常表达一定的语义。对于每个事件,EventEmitter支持若干个事件监听器。当事件触发时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递。

//event.js 文件
var events = require('events'); 
var emitter = new events.EventEmitter(); 
emitter.on('someEvent', function(arg1, arg2) { 
    console.log('listener1', arg1, arg2); 
}); 
emitter.on('someEvent', function(arg1, arg2) { 
    console.log('listener2', arg1, arg2); 
}); 
emitter.emit('someEvent', 'arg1 参数', 'arg2 参数'); 

# 运行结果
$ node event.js 
listener1 arg1 参数 arg2 参数
listener2 arg1 参数 arg2 参数

6.Nodejs Buffer(缓冲区)

JavaScript 语言自身只有字符串数据类型,没有二进制数据类型。

但在处理像TCP流或文件流时,必须使用到二进制数据。因此在 Node.js中,定义了一个 Buffer 类,该类用来创建一个专门存放二进制数据的缓存区。

Buffer与字符编码:

Buffer实例一般用于表示编码字符的序列,比如UTF-8、USC2、Base64、或十六进制编码的数据。通过使用显式地字符编码,就可以再Buffer实例与普通地JavaScript字符串之间进行相互转换。

const buf = Buffer.from('runoob', 'ascii');

// 输出 72756e6f6f62
console.log(buf.toString('hex'));

// 输出 cnVub29i
console.log(buf.toString('base64'));

Node.js 目前支持的字符编码包括:

  • ascii - 仅支持 7 位 ASCII 数据。如果设置去掉高位的话,这种编码是非常快的。
  • utf8 - 多字节编码的 Unicode 字符。许多网页和其他文档格式都使用 UTF-8 。
  • utf16le - 2 或 4 个字节,小字节序编码的 Unicode 字符。支持代理对(U+10000 至 U+10FFFF)。
  • ucs2 - utf16le 的别名。
  • base64 - Base64 编码。
  • latin1 - 一种把 Buffer 编码成一字节编码的字符串的方式。
  • binary - latin1 的别名。

创建Buffer类:

// 创建一个长度为 10、且用 0 填充的 Buffer。
const buf1 = Buffer.alloc(10);

// 创建一个长度为 10、且用 0x1 填充的 Buffer。 
const buf2 = Buffer.alloc(10, 1);

// 创建一个长度为 10、且未初始化的 Buffer。
// 这个方法比调用 Buffer.alloc() 更快,
// 但返回的 Buffer 实例可能包含旧数据,
// 因此需要使用 fill() 或 write() 重写。
const buf3 = Buffer.allocUnsafe(10);

// 创建一个包含 [0x1, 0x2, 0x3] 的 Buffer。
const buf4 = Buffer.from([1, 2, 3]);

// 创建一个包含 UTF-8 字节 [0x74, 0xc3, 0xa9, 0x73, 0x74] 的 Buffer。
const buf5 = Buffer.from('tést');

// 创建一个包含 Latin-1 字节 [0x74, 0xe9, 0x73, 0x74] 的 Buffer。
const buf6 = Buffer.from('tést', 'latin1');

写入缓冲区:

buf = Buffer.alloc(256);
len = buf.write("www.runoob.com");

console.log("写入字节数 : "+  len);

从缓冲区读取数据:

buf = Buffer.alloc(26);
for (var i = 0 ; i < 26 ; i++) {
  buf[i] = i + 97;
}

console.log( buf.toString('ascii'));       // 输出: abcdefghijklmnopqrstuvwxyz
console.log( buf.toString('ascii',0,5));   // 输出: abcde
console.log( buf.toString('utf8',0,5));    // 输出: abcde
console.log( buf.toString(undefined,0,5)); // 使用 'utf8' 编码, 并输出: abcde

将Buffer转换为JSON对象:

const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]);
const json = JSON.stringify(buf);

// 输出: {"type":"Buffer","data":[1,2,3,4,5]}
console.log(json);

const copy = JSON.parse(json, (key, value) => {
  return value && value.type === 'Buffer' ?
    Buffer.from(value.data) :
    value;
});

// 输出: <Buffer 01 02 03 04 05>
console.log(copy);

7.Nodejs Stream(流)

Stream 是一个抽象接口,Node 中有很多对象实现了这个接口。例如,对http 服务器发起请求的request 对象就是一个 Stream,还有stdout(标准输出)。

Node.js,Stream 有四种流类型:

  • Readable - 可读操作。
  • Writable - 可写操作。
  • Duplex - 可读可写操作.
  • Transform - 操作被写入数据,然后读出结果。

所有的 Stream 对象都是 EventEmitter 的实例。常用的事件有:

  • data - 当有数据可读时触发。
  • end - 没有更多的数据可读时触发。
  • error - 在接收和写入过程中发生错误时触发。
  • finish - 所有数据已被写入到底层系统时触发。

从流中读取数据:

var fs = require("fs");
var data = '';

// 创建可读流
var readerStream = fs.createReadStream('input.txt');

// 设置编码为 utf8。
readerStream.setEncoding('UTF8');

// 处理流事件 --> data, end, and error
readerStream.on('data', function(chunk) {
   data += chunk;
});

readerStream.on('end',function(){
   console.log(data);
});

readerStream.on('error', function(err){
   console.log(err.stack);
});

console.log("程序执行完毕");

写入流:

var fs = require("fs");
var data = '菜鸟教程官网地址:www.runoob.com';

// 创建一个可以写入的流,写入到文件 output.txt 中
var writerStream = fs.createWriteStream('output.txt');

// 使用 utf8 编码写入数据
writerStream.write(data,'UTF8');

// 标记文件末尾
writerStream.end();

// 处理流事件 --> data, end, and error
writerStream.on('finish', function() {
    console.log("写入完成。");
});

writerStream.on('error', function(err){
   console.log(err.stack);
});

console.log("程序执行完毕");

管道流:

管道提供了一个输出流到输入流的机制。通常我们用于从一个流中获取数据并将数据传递到另一个流中。

var fs = require("fs");

// 创建一个可读流
var readerStream = fs.createReadStream('input.txt');

// 创建一个可写流
var writerStream = fs.createWriteStream('output.txt');

// 管道读写操作
// 读取 input.txt 文件内容,并将内容写入到 output.txt 文件中
readerStream.pipe(writerStream);

console.log("`
序执行完毕");

链式流:

链式是通过连接输出流到另外一个流并创建多个流操作链的机制。链式流一般用于管道操作。

接下来我们就是用管道和链式来压缩和解压文件。

var fs = require("fs");
var zlib = require('zlib');

// 压缩 input.txt 文件为 input.txt.gz
fs.createReadStream('input.txt')
  .pipe(zlib.createGzip())
  .pipe(fs.createWriteStream('input.txt.gz'));

console.log("文件压缩完成。");

8.Nodejs 模块系统

创建模块:

var hello = require('./hello');
hello.world();

以上实例中,代码require(‘./hello’)引入了当前目录下的hello.js文件(./为当前目录,nodejs默认后缀为js)。

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

接下来我们就来创建hello.js文件,代码如下:

exports.world = function(){
    console.log('Hello World');
}

在以上实例中,hello.js通过exports对象把world作为模块的访问接口,在main.js中通过require(‘./hello’)加载这个模块,然后就可以直接访问hello.js在exports对象的成员函数了。

有时候我们只是想把一个对象封装到模块中,格式如下:

module.exports = function() {
  // ...
}

例如:

//hello.js 
function Hello() { 
    var name; 
    this.setName = function(thyName) { 
        name = thyName; 
    }; 
    this.sayHello = function() { 
        console.log('Hello ' + name); 
    }; 
}; 

module.exports = Hello;
这样就可以直接获得这个对象了:

//main.js 
var Hello = require('./hello'); 
hello = new Hello(); 
hello.setName('BYVoid'); 
hello.sayHello(); 

模块接口的唯一变化是使用 module.exports = Hello 代替了exports.world = function(){}。 在外部引用该模块时,其接口对象就是要输出的 Hello 对象本身,而不是原先的 exports。

9.Nodejs 函数

在JavaScript中,一个函数可以作为另一个函数的参数。我们可以先定义一个函数,然后传递,也可以在传递参数的地方直接定义函数。

Node.js中函数的使用与Javascript类似,举例来说,你可以这样做:

function say(word) {
  console.log(word);
}

function execute(someFunction, value) {
  someFunction(value);
}

execute(say, "Hello");

以上代码中,我们把 say 函数作为execute函数的第一个变量进行了传递。这里传递的不是 say 的返回值,而是 say 本身!

这样一来, say 就变成了execute 中的本地变量 someFunction ,execute可以通过调用 someFunction() (带括号的形式)来使用 say 函数。

当然,因为 say 有一个变量, execute 在调用 someFunction 时可以传递这样一个变量。

10.Nodejs 路由

var express = require('express');
var app = express();

//  主页输出 "Hello World"
app.get('/', function (req, res) {
   console.log("主页 GET 请求");
   res.send('Hello GET');
})


//  POST 请求
app.post('/', function (req, res) {
   console.log("主页 POST 请求");
   res.send('Hello POST');
})

//  /del_user 页面响应
app.get('/del_user', function (req, res) {
   console.log("/del_user 响应 DELETE 请求");
   res.send('删除页面');
})

//  /list_user 页面 GET 请求
app.get('/list_user', function (req, res) {
   console.log("/list_user GET 请求");
   res.send('用户列表页面');
})

// 对页面 abcd, abxcd, ab123cd, 等响应 GET 请求
app.get('/ab*cd', function(req, res) {   
   console.log("/ab*cd GET 请求");
   res.send('正则匹配');
})


var server = app.listen(8081, function () {

  var host = server.address().address
  var port = server.address().port

  console.log("应用实例,访问地址为 http://%s:%s", host, port)

})

11.Nodejs 工具模块

在Nodejs模块库中有很多好用的模块。

比如OS模块,Path模块,Net模块,DNS模块,Domain模块。

猜你喜欢

转载自blog.csdn.net/u014465934/article/details/81139203