Nodejs简介

148 阅读9分钟

nodejs简介

概述

Node.js 采用 Google 开发的 V8 运行代码,使用事件驱动、非阻塞和异步输入输出模型等技术来提高性能,可优化应用程序的传输量和规模。这些技术通常用于数据密集的即时应用程序(javascript 写的后端语言)

特点

  • 一个JavaScript运行环境
  • 依赖于Chrome V8引擎运行代码解释
  • 事件驱动: 在 Node.js 中,客户端请求建立连接,提交数据等行为,会触发相应的事件。Node.js 在一个时刻,只能执行一个事件回调函数,但是在执行一个事件回调函数的中途,可以转而处理其他事件,然后返回继续执行原事件的回调函数
  • 非阻塞IO
  • 轻量可伸缩: 适用于实时数据交互
  • 单线程

安装

自行百度或者google

  • 常用命令
node -v 查看安装的node版本
npm -v  查看包安装工具的版本
node; 进入命令行环境(类似于python)可运行简单的命令

node js 全局对象

Node js 中全局对象是global。所有全局对象(除了global本身以外)都是global对象的属性,我们可以直接访问global的属性

常见的全局变量

  • __filename
表示当前正在执行的脚本的文件名。它将输出文件所在位置的绝对路径,且和命令行参数所指定的文件名不一定相同
console.log(__filename)
  • __dirname
表示当前执行脚本所在的目录。

Hello,world

var http = require("http"); // 加载 http 模块,并将实例化的 HTTP 赋值给变量 http

http
  .createServer(function (request, response) {
    // 发送 HTTP 头部
    // HTTP 状态值: 200 : OK
    // 内容类型: text/plain
    response.writeHead(200, { "Content-Type": "text/plain" });

    response.end("Hello World\n"); // 发送响应数据 "Hello World"
  })
  .listen(8080);

// 终端打印如下信息
console.log("Server running at http://127.0.0.1:8080/");

打开浏览器输入127.0.0.1:8080

可以看到

Hello World

魅力所在: 简单几行代码即可开启一个简易服务器(nice)

Node.js包

用于管理多个模块及其依赖关系,包的根目录必须包含package.json,一般包含以下字段

  1. name:包名。包名是唯一的,只能包含小写字母、数字和下划线。
  2. version:包版本号。
  3. description:包说明。
  4. keywords:关键字数组,用于搜索。
  5. homepage:项目主页。
  6. bugs:提交 bug 的地址。
  7. license:许可证。
  8. maintainers:维护者数组。
  9. contributors:贡献者数组。
  10. repositories:项目仓库托管地址数组。
  11. dependencies:包依赖。

示例代码

{
  "name": "guiXu",
  "description": "nodejs项目",
  "version": "0.1.0",
  "keywords": ["GuiXu", "nodejs"],
  "maintainers": [
    {
      "name": "xx",
      "email": "xx"
    }
  ],
  "contributors": [
    {
      "name": "xx",
      "web": "xxx"
    }
  ],
  "bugs": {
    "mail": "xx",
    "web": "xxx"
  },
  "licenses": [
    {
      "type": "Apache License v2",
      "url": "http://www.apache.org/licenses/apache2.html"
    }
  ],
  "repositories": [
    {
      "type": "git",
      "url": "http://github.com/test/test.git"
    }
  ],
  "dependencies": {
    "webkit": "1.2",
    "ssl": {
      "gnutls": ["1.0", "2.0"],
      "openssl": "0.9.8"
    }
  }
}

创建方式:

  • 手动创建
  • npm init命令创建

包命令:

npm install 包名 安装包
npm uodate 包名 更新包
npm uninstall 包名 删除包

模块

一个单独的js文件可被看做一个模块,但想在其他地方使用必须包含导入和导出

导出: module.exports
导入: require(文件路径) require为加载模块

Node.js事件

大多数 Node.js 核心 API 构建于惯用的异步事件驱动架构,其中某些类型的对象(又称触发器,Emitter)会触发命名事件来调用函数(又称监听器,Listener)。

所有能触发事件的对象都是 EventEmitter 类的实例。这些对象有一个 eventEmitter.on() 函数,用于将一个或多个函数绑定到命名事件上。当 EventEmitter 对象触发一个事件时,所有绑定在该事件上的函数都会被同步地调用

EventEmitter类获取

// 引入 events 模块
var events = require("events");
// 创建 eventEmitter 对象
var eventEmitter = new events.EventEmitter();
  • 添加监听器

emitter.on(eventName, listener)

使用 emitter.on(eventName, listener) 方法为指定事件注册一个监听器。添加 listener 函数到名为 eventName 的事件的监听器数组的末尾。不会检查 listener 是否已被添加。多次调用并传入相同的 eventName 与 listener 会导致 listener 会被添加多次。

demo

// 引入 events 模块
var events = require("events");
// 创建 emitter 对象
var emitter = new events.EventEmitter();
// 为 connection 事件注册一个监听器
emitter.on("connection", function () {
  console.log("已连接");
});
// 一秒后调用监听器
setTimeout(function () {
  emitter.emit("connection");
}, 1000);

emitter.prependListener() 方法可用于将事件监听器添加到监听器数组的开头

// 引入 events 模块
var events = require("events");
// 创建 server 对象
var emitter = new events.EventEmitter();
// 为 connection 事件注册一个监听器
emitter.on("connection", function () {
  console.log("我是a");
});
// 箭头函数,有兴趣的可以自行了解一下
emitter.prependListener("connection", () => console.log("我是b"));
// 一秒后调用监听器
setTimeout(function () {
  emitter.emit("connection");
}, 1000);
  • 调用监听器

使用 emitter.emit(eventName[, ...args]) 按照监听器注册的顺序,同步地调用每个注册到名为 eventName 的事件的监听器,并传入提供的参数。如果事件有注册监听返回 true,否则返回 false

// 引入 events 模块
var events = require("events");
// 创建 emitter 对象
var emitter = new events.EventEmitter();
// 定义一个回调函数
var callback1 = function (arg1, arg2) {
  console.log("hello world", arg1, arg2);
};
var callback2 = function (arg3, arg4) {
  console.log("hello stranger", arg3, arg4);
};
// 为 connection 事件注册监听器
emitter.on("connection", callback1);
emitter.on("connection", callback2);
// 调用监听器
emitter.emit("connection", "愿善良的人", "都能被温柔以待");
  • 只执行一次的监听器

eventEmitter.once(eventName, listener) 可以注册最多可调用一次的监听器

  • 移除监听器

emitter.removeListener(eventName, listener) 移除监听器。

  • 设置监听器最大绑定数

emitter.setMaxListeners(n) 设置同一事件的监听器最大绑定数。默认情况下,如果为特定事件添加了超过 10 个监听器,则 EventEmitter 会打印一个警告,这有助于我们发现内存泄露。显然实际编码中并不是所有的事件都要限制 10 个监听器。

  • 查看事件绑定的监听器个数

emitter.listenerCount(eventName) 查看事件绑定的监听器个数

http模块

http 模块主要用于搭建 HTTP 服务端和客户端,要使用 HTTP 服务器和客户端功能必须调用 http 模块

  • 创建服务器
http.createServer([requestListener]);

requestListener 是一个请求函数

函数传递有两个参数:request 请求对象 和 response 响应对象。我们调用 request 请求对象的属性和方法就可以拿到所有 HTTP 请求的信息,我们操作 response 响应对象的方法,就可以把 HTTP 响应返回给浏览器。

response 对象常用的方法有:

  • response.writeHead(statusCode[, statusMessage][, headers])。表示向请求发送响应头。

参数说明:

  • statusCode:状态码,是一个 3 位 HTTP 状态码,如 404 表示网页未找到,200 表示正常。
  • statusMessage:可选的,可以将用户可读的 statusMessage 作为第二个参数。
  • headers:响应头。也就是设置 Content-Type 的值,用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件。常用值有:(1)text/html:HTML 格式(2)text/plain:纯文本格式(3)application/x-www-form-urlencoded:数据被编码为名称/值对,这是标准的编码格式。其余的可以自行百度了解,比如 Content-Type 对照表
response.writeHead(200, { "Content-Type": "text/plain;charset=UTF-8" });
  • response.write() 发送一块响应主体,也就是说用来给客户端发送响应数据。可以直接写文本信息,也可以写我们的 html 代码,注意要设置 Content-Type 的值。write 可以使用多次,但是最后一定要使用 end 来结束响应,否则客户端会一直等待

  • response.end() 此方法向服务器发出信号,表示已发送所有响应头和主体,该服务器应该视为此消息完成。必须在每个响应上调用方法 response.end()

demo

// 加载 http 模块
var http = require("http");

// 创建服务器
http
  .createServer(function (request, response) {
    // 发送 HTTP 头部
    // HTTP 状态值: 200 : OK
    // 内容类型: text/html
    response.writeHead(200, { "Content-Type": "text/html;charset=UTF-8" });

    // 发送响应数据 'hello guixu'
    response.write("hello guixu");
    // 发送数据 hello world 并且字体为 h1 格式
    response.write("<h1>hello world</h1>");
    // 结束
    response.end();

    // 上面的三行代码也可以直接写成 response.end('hello guixu <h1>hello world</h1>');
  })
  .listen(8080);

// 终端打印如下信息
console.log("Server running at http://127.0.0.1:8080/");

request 对象:

  • request.url 获取请求路径,获取到的是端口号之后的那一部分路径,也就是说所有的 url 都是以 / 开头的,判断路径处理响应。

  • request.socket.localAddress 获取 ip 地址。

  • request.socket.remotePort 获取源端口。

// 1. 创建 Server
var server = http.createServer();

// 2. 监听 request 请求事件,设置请求处理函数
server.on("request", function (req, res) {
  console.log("收到请求了,请求路径是:" + req.url);
  console.log(
    "请求我的客户端的地址是:",
    req.socket.remoteAddress,
    req.socket.remotePort
  );
  var url = req.url;
  res.writeHead(200, { "Content-Type": "text/html;charset=UTF-8" });
  if (url === "/") {
    res.end("<h1>Index page</h1>");
  } else if (url === "/login") {
    res.end("<h1>Login page</h1>");
  } else {
    res.end("404 Not Found.");
  }
});

// 3. 绑定端口号,启动服务
server.listen(8080, function () {
  console.log("服务器启动成功,可以访问了。。。");
});

fs模块

文件操作

  • 打开文件
fs.open(path, flags[, mode], callback);

demo

// 引入 fs 模块
var fs = require("fs");
// 异步打开文件
fs.open("input.txt", "r+", function (err, fd) {
  if (err) {
    return console.error(err);
  }
  console.log("文件打开成功!");
});

此方式为异步方式

同步打开文件的语法

fs.openSync(path, flags[, mode])
  • 关闭文件
fs.close(fd, callback);
// 引入 fs 模块
var fs = require("fs");
// 异步打开文件
fs.open("test.txt", "r+", function (err, fd) {
  if (err) {
    return console.error(err);
  }
  console.log("文件打开成功!");
  // 异步关闭文件
  fs.close(fd, function (err) {
    if (err) {
      console.log(err);
    }
    console.log("文件关闭成功");
  });
});
  • 读写文件
fs.read(fd, buffer, offset, length, position, callback);
  + fd:通过 `fs.open()` 方法返回的文件描述符。
  + buffer:是数据写入的缓冲区。
  - offset:是缓冲区中开始写入的偏移量。一般它的值我们写为 0。
  - length:是一个整数,指定要读取的字节数。
  - position:指定从文件中开始读取的位置。如果 position 为 null,则从当前文件位置读取数据,并更新文件位置。
  - callback:回调函数,有三个参数 `(err, bytesRead, buffer)`。err 为错误信息,bytesRead 表示读取的字节数,buffer 为缓冲区对象。

demo

// 引入 fs 模块
var fs = require("fs");
// 异步打开文件
fs.open("test.txt", "r+", function (err, fd) {
  if (err) {
    return console.error(err);
  }
  console.log("文件打开成功!");
  console.log("准备读取文件:");
  // 创建一个大小为 1024 字节的缓存区
  var buf = Buffer.alloc(1024);
  // 异步读取文件
  fs.read(fd, buf, 0, buf.length, 0, function (err, bytes, buf) {
    if (err) {
      console.log(err);
    }
    console.log(bytes + "字节被读取");
    // 仅输出读取的字节
    if (bytes > 0) {
      console.log(buf.slice(0, bytes).toString());
    }
    // 异步关闭文件
    fs.close(fd, function (err) {
      if (err) {
        console.log(err);
      }
      console.log("文件关闭成功");
    });
  });
});

写入文件

fs.write(fd, buffer, offset, length, position, callback);

参数同读文件操作

// 引入 fs 模块
var fs = require("fs");
// 异步打开文件
fs.open("./test.txt", "a", function (err, fd) {
  if (err) {
    return console.error(err);
  }
  console.log("文件打开成功!");
  console.log("准备写入文件:");
  // 新写入内容为 hello world
  var buffer = Buffer.from(new String(" hello world"));
  // 异步写入文件
  fs.write(fd, buffer, 0, 12, 0, function (err, bytes, buffer) {
    if (err) {
      throw err;
    }
    console.log("写入成功");
    // 打印出 buffer 中存入的数据
    console.log(bytes + "字节被写入");
    console.log(buffer.slice(0, bytes).toString());
    // 异步关闭文件
    fs.close(fd, function (err) {
      if (err) {
        console.log(err);
      }
      console.log("文件关闭成功");
    });
  });
});
  • readFile 读取文件--异步
fs.readFile(path, [options], callback);
  • writeFile写入文件
fs.writeFile(file, data, [options], callback);