# Node.js学习(基础)

# 基础介绍

# 什么是node.js

  • Node.js的本质是一个javascript解析器
  • Node.js是javascript的运行环境
  • Node.js是一个服务器程序
  • Node.js本身使用的是V8引擎
  • Node.js不是web服务器

# 为什么要使用node.js

  • 为了提供高性能的web服务
  • IO性能强大
  • 时间处理机制完善
  • 天然能够处理DOM
  • 社区非常活跃,生态圈日趋完善

# node.js的优势在哪里

  • 处理大流量数据
  • 适合实时交互的应用
  • 完美支持对象数据库
  • 异步处理大量并发连接

# 学习node.js的前置知识

  • javascript
  • ES6
  • 一些服务器相关的知识
  • 最好在Linux系统下进行开发

# node.js相关的资源和资料

  • 官网网站
  • 中文社区
  • 手册
  • 开源代码

# Node.js回调函数

# 什么是回调

  • 函数调用方式分为三类:同步调用、回调和异步调用。
  • 回调是一种双向调用模式
  • 可以通过回调函数来实现回调

# 阻塞与非阻塞

  • 阻塞和非阻塞关注的是程序在等待调用结果(消息、返回值)时的状态
  • 阻塞就是做不完不准回来
  • 非阻塞就是你先做,我先看看有其他事没有,完了告诉我一声

阻塞代码

var fs = require('fs');
var data = fs.readFileSync('data.txt');
console.log(data.toString());
1
2
3

非阻塞代码

var fs = require('fs');
var data = fs.readFile('data.txt', function (err, data) {
	if (err) {
		return console.error(err);
	}
	console.log(data.toString());
});
console.log('程序执行完毕');
1
2
3
4
5
6
7
8

# Node.js事件驱动机制

# 事件驱动模型

在这里插入图片描述

# 事件处理代码流程

  1. 引入events 对象,创建eventEmitter对象
  2. 绑定事件处理程序
  3. 触发事件
//引入Event模块并创建eventsEmitter对象
var events = require('events');
var eventEmitter = new events.EventEmitter();

//绑定事件处理函数
var connectHandler = function connected() {
	console.log('connected被调用!');
}
eventEmitter.on('connection', connectHandler);//完成事件绑定
//触发事件
eventEmitter.emit('connection');
console.log(''程序执行完毕);

//输出结果
//connected被调用!
//程序执行完毕
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# Node.js模块化

# 模块化的概念与意义

  • 为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统
  • 模块是Node.js应用程序的基本组成部分
  • 文件和模块是一一对应的。一个Node.js文件就是一个模块
  • 这个文件可能是javascript代码、JSON或者编译过的C/C++拓展。
  • Node.js中存在4类模块(原生模块和3中文件模块)

# Node.js的模块加载流程

在这里插入图片描述

# Node.js的模块加载方式

  • 从文件模块缓存中加载
  • 从原生模块加载
  • 从文件加载

# require方法加载模块

require方法接受一下几种参数的传递:

  • http、fs、path等,原生模块
  • ./mod或../mod,相对路径的文件模块。
  • /pathtomodule/mod,绝对路径的文件模块。
  • mod,非原生模块的文件模块

hello.js

//模块的主要逻辑
function Hello() {
	var name;
	this.setName = function(argName) {
		name = argName;
	}
	this.sayHello = function() {
		console.log('Hello' + name);
	}
}
//对模块进行导出
module.exports = Hello;
1
2
3
4
5
6
7
8
9
10
11
12

main.js

//调用Hello模块
var Hello = require('./hello');
hello = new Hello();
hello.setName('Yideng');
hello.sayHello();
//输出
//Hello Yideng
1
2
3
4
5
6
7

# Node.js函数

# 函数概念

  • 在javascript中,一个函数可以作为另一个函数的参数
  • 我们可以先定义一个函数,然后传递,也可以再传递参数的地方直接定义函数
  • Node.js中函数的使用与javascript类似

# 函数举例

function say (word) {
	console.log(word);
}
function execute (someFunction, value) {
	someFunction(value);
}
execute(say, "Hello");
1
2
3
4
5
6
7

# 匿名函数

  • 我们可以把一个函数作为变量传递
  • 不一定“先定义,在传递”,可以直接在另一个函数的括号中定义和传递这个函数。
function excute(someFunction, value) {
	someFunction(value);
}
execute(function(word) {console.log(word)}, "Hello");
1
2
3
4
//同样的功能,不同的实现方式
//匿名函数
var http = require("http");
http.creatServer(function(request, response) {
	response.writeHead(200, {"Content-Type": "text/plain"});
	response.write("Hello World");
	response.end();
}).listen(8888);

////////////////////
//先定义后传递
var http = require("http");
function onRequest(request, response) {
	response.writeHead(200, {"Content-Type": "text/plain"});
	response.write("Hello World");
	response.end();
}
http.createServer(onRequest).listen(8888);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# Node.js路由

server.js

var http = require("http");
var url = require("url");

function start(route) {
    function onRequest(request, response) {
        var pathname = url.parse(request.url).pathname;

        route(pathname, response);
    }

    http.createServer(onRequest).listen(8888);
    console.log("Server has started.");
}

exports.start = start;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

router.js

function route(pathname, response) {
    console.log("About to route a request for " + pathname);
    if (pathname == '/') {
        response.writeHead(200, {
            "Content-Type": "text/plain"
        });
        response.write("Hello World");
        response.end();
    } else {
        response.end(`${pathname}`);
    }
}

exports.route = route;
1
2
3
4
5
6
7
8
9
10
11
12
13
14

index.js

var server = require("./server");
var router = require("./router");
 
server.start(router.route);
1
2
3
4

# Node.js全局对象

Node.js全局对象

# Node.js文件系统

# 打开文件

var fs = require("fs");

// 异步打开文件
console.log("准备打开文件!");
fs.open('input.txt', 'r+', function(err, fd) {
   if (err) {
       return console.error(err);
   }
  console.log("文件打开成功!");     
});
1
2
3
4
5
6
7
8
9
10

执行

$ node file.js 
准备打开文件!
文件打开成功!
1
2
3

# 获取文件信息

var fs = require("fs");

console.log("准备打开文件!");
fs.stat('input.txt', function (err, stats) {
   if (err) {
       return console.error(err);
   }
   console.log(stats);
   console.log("读取文件信息成功!");
   
   // 检测文件类型
   console.log("是否为文件(isFile) ? " + stats.isFile());
   console.log("是否为目录(isDirectory) ? " + stats.isDirectory());    
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14

执行结果

$ node file.js 
准备打开文件!
{ dev: 16777220,
  mode: 33188,
  nlink: 1,
  uid: 501,
  gid: 20,
  rdev: 0,
  blksize: 4096,
  ino: 40333161,
  size: 61,
  blocks: 8,
  atime: Mon Sep 07 2015 17:43:55 GMT+0800 (CST),
  mtime: Mon Sep 07 2015 17:22:35 GMT+0800 (CST),
  ctime: Mon Sep 07 2015 17:22:35 GMT+0800 (CST) }
读取文件信息成功!
是否为文件(isFile) ? true
是否为目录(isDirectory) ? false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 读取文件

var fs = require("fs");
var buf = new Buffer.alloc(1024);

console.log("准备打开已存在的文件!");
fs.open('input.txt', 'r+', function(err, fd) {
   if (err) {
       return console.error(err);
   }
   console.log("文件打开成功!");
   console.log("准备读取文件:");
   fs.read(fd, buf, 0, buf.length, 0, function(err, bytes){
      if (err){
         console.log(err);
      }
      console.log(bytes + "  字节被读取");
      
      // 仅输出读取的字节
      if(bytes > 0){
         console.log(buf.slice(0, bytes).toString());
      }
   });
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

执行结果

$ node file.js 
准备打开已存在的文件!
文件打开成功!
准备读取文件:
42  字节被读取
菜鸟教程官网地址:www.runoob.com
1
2
3
4
5
6

# 写入文件

var fs = require("fs");

console.log("准备写入文件");
fs.writeFile('input.txt', '我是通 过fs.writeFile 写入文件的内容',  function(err) {
   if (err) {
       return console.error(err);
   }
   console.log("数据写入成功!");
   console.log("--------我是分割线-------------")
   console.log("读取写入的数据!");
   fs.readFile('input.txt', function (err, data) {
      if (err) {
         return console.error(err);
      }
      console.log("异步读取文件数据: " + data.toString());
   });
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

执行结果

$ node file.js 
准备写入文件
数据写入成功!
--------我是分割线-------------
读取写入的数据!
异步读取文件数据: 我是通 过fs.writeFile 写入文件的内容
1
2
3
4
5
6

# 关闭文件

var fs = require("fs");
var buf = new Buffer.alloc(1024);

console.log("准备打开文件!");
fs.open('input.txt', 'r+', function(err, fd) {
   if (err) {
       return console.error(err);
   }
   console.log("文件打开成功!");
   console.log("准备读取文件!");
   fs.read(fd, buf, 0, buf.length, 0, function(err, bytes){
      if (err){
         console.log(err);
      }

      // 仅输出读取的字节
      if(bytes > 0){
         console.log(buf.slice(0, bytes).toString());
      }

      // 关闭文件
      fs.close(fd, function(err){
         if (err){
            console.log(err);
         } 
         console.log("文件关闭成功");
      });
   });
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

执行结果

$ node file.js 
准备打开文件!
文件打开成功!
准备读取文件!
菜鸟教程官网地址:www.runoob.com
文件关闭成功
1
2
3
4
5
6

# 截取文件

var fs = require("fs");
var buf = new Buffer.alloc(1024);

console.log("准备打开文件!");
fs.open('input.txt', 'r+', function(err, fd) {
   if (err) {
       return console.error(err);
   }
   console.log("文件打开成功!");
   console.log("截取10字节内的文件内容,超出部分将被去除。");
   
   // 截取文件
   fs.ftruncate(fd, 10, function(err){
      if (err){
         console.log(err);
      } 
      console.log("文件截取成功。");
      console.log("读取相同的文件"); 
      fs.read(fd, buf, 0, buf.length, 0, function(err, bytes){
         if (err){
            console.log(err);
         }

         // 仅输出读取的字节
         if(bytes > 0){
            console.log(buf.slice(0, bytes).toString());
         }

         // 关闭文件
         fs.close(fd, function(err){
            if (err){
               console.log(err);
            } 
            console.log("文件关闭成功!");
         });
      });
   });
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

执行结果

$ node file.js 
准备打开文件!
文件打开成功!
截取10字节内的文件内容,超出部分将被去除。
文件截取成功。
读取相同的文件
site:www.r
文件关闭成功
1
2
3
4
5
6
7
8

# 删除文件

var fs = require("fs");

console.log("准备删除文件!");
fs.unlink('input.txt', function(err) {
   if (err) {
       return console.error(err);
   }
   console.log("文件删除成功!");
});
1
2
3
4
5
6
7
8
9

执行结果

$ node file.js 
准备删除文件!
文件删除成功!
1
2
3

# 创建目录

var fs = require("fs");
// tmp 目录必须存在
console.log("创建目录 /tmp/test/");
fs.mkdir("/tmp/test/",function(err){
   if (err) {
       return console.error(err);
   }
   console.log("目录创建成功。");
});
1
2
3
4
5
6
7
8
9

执行结果

$ node file.js 
创建目录 /tmp/test/
目录创建成功。
1
2
3

# 读取目录

var fs = require("fs");

console.log("查看 /tmp 目录");
fs.readdir("/tmp/",function(err, files){
   if (err) {
       return console.error(err);
   }
   files.forEach( function (file){
       console.log( file );
   });
});
1
2
3
4
5
6
7
8
9
10
11

执行结果

$ node file.js 
查看 /tmp 目录
input.out
output.out
test
test.txt
1
2
3
4
5
6

# 删除目录

var fs = require("fs");
// 执行前创建一个空的 /tmp/test 目录
console.log("准备删除目录 /tmp/test");
fs.rmdir("/tmp/test",function(err){
   if (err) {
       return console.error(err);
   }
   console.log("读取 /tmp 目录");
   fs.readdir("/tmp/",function(err, files){
      if (err) {
          return console.error(err);
      }
      files.forEach( function (file){
          console.log( file );
      });
   });
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

执行结果

$ node file.js 
准备删除目录 /tmp/test
读取 /tmp 目录
……
1
2
3
4

更多详情

更新时间: 11/8/2019, 4:51:43 PM