Nodejs 入门基础

简介: Nodejs 入门基础

1. NodeJs 简介

Nodejs介绍

Node.js 是一个 Javascript 运行环境(runtime)。它让 JavaScript 可以开发后端程序,实现几乎其他后端语言实现的所有功能,可以与 PHP、JSP、Python、Ruby 等后端语言平起平坐。

Nodejs 是基于 V8 引擎,V8 是 Google 发布的开源 JavaScript 引擎,本身就是用于 Chrome 浏览器的 JS 解释部分,但是 Ryan Dahl 这哥们,鬼才般的,把这个 V8 搬到了服务器上,用于做服务器的软件。

Node优势

NodeJs 语法完全是 js 语法,只要懂 JS 基础就可以学会 Nodejs 后端开发

这打破了过去 JavaScript 只能在浏览器中运行的局面。前后端编程环境统一,可以大大降低开发成本。


NodeJs 超强的高并发能力

Node.js 的首要目标是提供一种简单的、用于创建高性能服务器及可在该服务器中运行的各种应用程序的开发工具。在 Java、PHP 或者.net 等服务器端语言中,会为每一个客户端连接创建一个新的线程。而每个线程需要耗费大约 2MB 内存。也就是说,理论上,一个 8GB 内存的服务器可以同时连接的最大用户数为 4000 个左右,而Node.js 不为每个客户连接创建一个新的线程,而仅仅使用一个线程。当有用户连接了,就触发一个内部事件,通过非阻塞 I/O、事件驱动机制,让 Node.js 程序宏观上也是并行的。使用 Node.js,一个 8GB内存的服务器,可以同时处理超过 4 万用户的连接。


实现高性能服务器。

严格地说,Node.js 是一个用于开发各种 Web 服务器的开发工具。在 Node.js 服务器中,运行的是高性能 V8JavaScript 脚本语言,该语言是一种可以运行在服务器端的 JavaScript 脚本语言。

那么,什么是 V8 JavaScript 脚本语言呢?该语言是一种被 V8 JavaScript 引擎所解析并执行的脚本语言。V8JavaScript 引擎是由 Google 公司使用 C++语言开发的一种高性能 JavaScript 引擎,该引擎并不局限于在浏览器中运行。Node.js 将其转用在了服务器中,并且为其提供了许多附加的具有各种不同用途的 API。

例如,在一个服务器中,经常需要处理各种二进制数据。在 JavaScript 脚本语言中,只具有非常有限的对二进制数据的处理能力,而 Node.js 所提供的 Buffer 类则提供了丰富的对二进制数据的处理能力。另外,在 V8 JavaScript 引擎内部使用一种全新的编译技术。这意味着开发者编写的高端的 JavaScript 脚本代码与开发者编写的低端的 C语言具有非常相近的执行效率,这也是 Node.js 服务器可以提供的一个重要特性。

Node环境的搭建

nodejs 官网

2. NodeJs HTTP 模块、URL 模块

2.1 Node.js 创建第一个应用

如果我们使用 PHP 来编写后端的代码时,需要 Apache 或者 Nginx 的 HTTP 服务器,来处理客户端的请求相应。不过对 Node.js 来说,概念完全不一样了。使用 Node.js 时,我们不仅仅在实现一个应用,同时还实现了整个 HTTP 服务器。

引入 http 模块

var http = require("http");

创建服务器

接下来我们使用 http.createServer() 方法创建服务器,并使用 listen 方法绑定 8888 端口。

函数通过 request, response 参数来接收和响应数据。

var http = require('http');
http.createServer(function (request, response) {
// 发送 HTTP 头部
// HTTP 状态值: 200 : OK
//设置 HTTP 头部,状态码是 200,文件类型是 html,字符集是 utf8
response.writeHead(200,{"Content-Type":"text/html;charset=UTF-8"});
// 发送响应数据 "Hello World"
res.end("这是第一个node应用");
}).listen(3000);

运行程序

用命令行切换到程序对应目录。通过 node 命令运行程序。

node xxx.js

你会发现,我们本地写一个 js,打死都不能直接拖入浏览器运行,但是有了 node,我们任何一个 js 文件,都可以通过 node 来运行。也

就是说,node 就是一个 js 的执行环境。

2.2 HTTP 模块的使用

Node.js 中,将很多的功能,划分为了一个个 module(模块)。 Node.js 中的很多功能都是通过模块实现。

//引用模块
var http = require("http");
//创建一个服务器,回调函数表示接收到请求之后做的事情
var server = http.createServer(function(req,res){
  //req 参数表示请求,res 表示响应
  console.log("服务器接收到了请求" + req.url);
  res.end(); // End 方法使 Web 服务器停止处理脚本并返回当前结果
});
//监听端口
server.listen(3000);

设置一个响应头

//引用模块
var http = require("http");
//创建一个服务器,回调函数表示接收到请求之后做的事情
http.createServer(function(req,res){
  //req 参数表示请求,res 表示响应
  res.writeHead(200,{"Content-Type":"text/html;charset=UTF8"});//插入响应头
  console.log("服务器接收到了请求" + req.url);
  res.end(); // End 方法使 Web 服务器停止处理脚本并返回当前结果
}).listen(3000);

现在来看一下 req 里面能够使用的东西。最关键的就是 req.url 属性,表示用户的请求 URL 地址。

所有的路由设计,都是通过 req.url来实现的。我们比较关心的不是拿到 URL,而是识别这个 URL。识别 URL,用到了下面的 url 模块。

2.3 URL 模块的使用

const url = require('url');
url.parse()  // 解析 URL
url.format(urlObject) // 是上面 url.parse() 操作的逆向操作
url.resolve(from, to) // 添加或者替换地址

小案例:

const http = require('http');
const url = require('url');
// 模拟客户端请求地址: http://127.0.0.1:8081/?name=%27test%27&age=12
http.createServer((req, res) => {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  if(req.url != '/favicon.ico'){ 
    var userInfo = url.parse(req.url,true).query;
    console.log(`姓名:${userInfo.name}---年龄:${userInfo.age}`) // 姓名:'test'---年龄:12
  }
  res.end('hello nodejs');
}).listen(8081);

3. CommonJs 和 Nodejs 中自定义模块

什么是Common.js?

JavaScript 是一个强大面向对象语言,它有很多快速高效的解释器。然而, JavaScript标准定义的 API 是为了构建基于浏览器的应用程序。并没有制定一个用于更广泛的应用程序的标准库。CommonJS 规范的提出,主要是为了弥补当前 JavaScript 没有标准的缺陷。它的终极目标就是:提供一个类似 Python,Ruby 和 Java 语言的标准库,而不只是停留在小脚本程序的阶段。CommonJS 就是模块化的标准,nodejs 就是 CommonJS(模块化)的实现。

2.1 Nodejs 中的模块化

Node 应用由模块组成,采用 CommonJS 模块规范。

在 Node 中,模块分为两类:

一类是 Node 提供的模块,称为核心模块;另一类是用户编写的模块,称为文件模块;

• 核心模块部分在 Node 源代码的编译过程中,编译进了二进制执行文件。在 Node 进程启动时,部分核心模块就被直接加载进内存中,所以这部分核心模块引入时,文件定位和编译执行这两个步骤可以省略掉,并且在路径分析中优先判断,所以它的加载速度是最快的。如:HTTP 模块 、URL 模块、Fs 模块都是 nodejs 内置的核心模块,可以直接引入使用。

• 文件模块则是在运行时动态加载,需要完整的路径分析、文件定位、编译执行过程、速度相比核心模块稍微慢一些,但是用的非常多。这些模块需要我们自己定义。


CommonJS(Nodejs)中自定义模块的规定:

• 我们可以把公共的功能抽离成为一个单独的 js 文件作为一个模块,默认情况下面这个模块里面的方法或者属性,外面是没法访问的。如果要让外部可以访问模块里面的方法或者属性,就必须在模块里面通过 exports 或者 module.exports 暴露属性或者方法。

• 在需要使用这些模块的文件中,通过 require 的方式引入这个模块。这个时候就可以使用模块里面暴露的属性和方法。


定义使用模块:

// 定义一个 tools.js 的模块
//模块定义
var tools = {
  sayHello: function() {
    return 'hello NodeJS';
  },
  add: function(x, y) { 
    return x + y;
  }
};
// 模块接口的暴露
// module.exports = tools;
exports.sayHello = tools.sayHello;
exports.add = tools.add;
var http = require('http');
// 引入自定义的 tools.js 模块
var tools = require('./tools');
tools.sayHello(); //使用模块
  1. npm init 生成 package.json

package.json内保存了应用信息,比如版本,依赖,环境等


npm init 
eg:
{
  "name": "axios",
  "version": "1.0.0",
  "main": "axios.js",  // 项目入口
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "keywords": [],
  "description": ""
}
  1. 完全符合 CommonJs 规范的包目录一般包含以下文件:
    package.json: 包描述文件;
    bin: 用于存放可执行的二进制文件的目录;
    lib: 用于存放JavaScript代码的目录;
    doc: 用于存放文档的目录;

4. NodeJs FS 模块

使用前先引入 fs 模块

const fs = require('fs')

4.1 fs.stat 检测是文件还是目录

fs.stat('hello.js', (error, stats) =>{
 if(error){
  console.log(error)
 } else {
  console.log(stats)
  console.log(`文件:${stats.isFile()}`)
  console.log(`目录:${stats.isDirectory()}`) }
})

4.2 fs.mkdir 创建目录

/**
  path         将创建的目录的路径;
  mode         目录权限(读写权限),默认777;
  callback     回调,传递异常参数err;
**/
fs.mkdir('logs', (error) => {
 if(error){
  console.log(error)
 } else {
  console.log('成功创建目录:logs') }
})

4.3 fs.writeFile 创建写入文件

/**
filename          (string)               文件名称
data          (string|buffer)          将要写入的内容,可以是字符串 或 buffer 数据;
options          (object)              option 数组对象,包含:
  encoding     (string)                  可选值,默认 utf8
  mode         (number)                  文件读写权限,默认值 438
  flag         (string)                  默认值 ‘w’
callback        {function}              回调,传递一个异常参数 err  
**/
fs.writeFile('logs/hello.log', '您好 ~ \n', (error) => {
 if(error) {
  console.log(error)
 } else {
  console.log('成功写入文件') }
})

4.4 fs.appendFile 追加文件

fs.appendFile('logs/hello.log', 'hello ~ \n', (error) => {
 if(error) {
  console.log(error)
 } else {
  console.log('成功写入文件') }
})

4.5 fs.readFile 读取文件

fs.readFile('logs/hello.log', 'utf8', (error, data) =>{
  if (error) {
     console.log(error)
  } else {
    console.log(data)
  }
})

4.6 fs.readdir 读取目录

fs.readdir('logs', (error, files) => {
  if (error) {
    console.log(error)
  } else {
    console.log(files)
  }
})

4.7 fs.rename 重命名 、移动文件

fs.rename('js/hello.log', 'js/greeting.log', (error) =>{
  if (error) {
    console.log(error)
   } else {
      console.log('重命名(移动文件)成功') }
})

4.8 fs.rmdir 删除目录

fs.rmdir('logs', (error) =>{
  if (error) {
     console.log(error)
  } else {
     console.log('成功的删除了目录:logs') }
})

4.9 fs.unlink 删除文件

fs.unlink(`logs/${file}`, (error) => {
  if (error) {
     console.log(error)
  } else {
     console.log(`成功的删除了文件: ${file}`) }
})

mkdirp:一款在 node.js 中递归创建目录及其子目录的插件

4.10 fs.createReadStream 从文件流中读取数据

const fs = require('fs')
var fileReadStream = fs.createReadStream('./test.txt')
let count = 0;
var str='';
fileReadStream.on('data', (chunk) => {
  console.log(`${ ++count } 接收到:${chunk.length}`);
  str+=chunk
})
fileReadStream.on('end', () => {
  console.log('--- 结束 ---');
  console.log(count);
  console.log(str);
})
fileReadStream.on('error', (error) => {
  console.log(error)
})

4.11 fs.createWriteStream 以文件流的方式写入文件

var fs = require("fs");
var str = '';
for(let i = 0 ; i < 200; i++){
  str += '我是从数据库获取的数据,我要保存起来\n'
}
// 创建一个可以写入的流,写入到文件 output.txt 中
var writerStream = fs.createWriteStream('./output.txt');
// 使用 utf8 编码写入数据
writerStream.write(str,'UTF8');
// 标记文件末尾
writerStream.end();
// 处理流事件 --> finish 事件
writerStream.on('finish', () => { /*finish - 所有数据已被写入到底层系统时触发。*/
  console.log("写入完成");
}); 
writerStream.on('error', (err) => {
  console.log(err.stack);
});

4.12 管道流

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

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 readerStream = fs.createReadStream('./test.zip');
// 创建一个可写流
var writerStream = fs.createWriteStream('./test/testNew.zip');
// 管道读写操作
// 读取 input.txt 文件内容,并将内容写入到 output.txt 文件中
readerStream.pipe(writerStream);
console.log("程序执行完毕");

5. 非阻塞 IO、异步、事件驱动基础

5.1 单线程 非阻塞 I/O 事件驱动

在 Java、PHP 或者.net 等服务器端语言中,会为每一个客户端连接创建一个新的线程。而每个线程需要耗费大约 2MB 内存。也就是说,理论上,一个 8GB 内存的服务器可以同时连接的最大用户数为 4000 个左右。要让 Web 应用程序支持更多的用户,就需要增加服务器的数量,而 Web 应用程序的硬件成本当然就上升了。Node.js 不为每个客户连接创建一个新的线程,而仅仅使用一个线程。当有用户连接了,就触发一个内部事件,通过非阻塞 I/O、事件驱动机制,让 Node.js 程序宏观上也是并行的。使用 Node.js,一个 8GB 内存的服务器,可以同时处理超过 4 万用户的连接。

5.2 Nodejs 回调处理异步

//正确的处理异步:
function getData(callback){
  //模拟请求数据
  var result = '';
  setTimeout(function(){
    result = '这是请求到的数据';
    callback(result);
  },200);
}
getData(function(data){
  console.log(data);
})

5.3 Nodejs events 模块处理异步

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

// 引入 events 模块
var events = require('events');
var EventEmitter = new events.EventEmitter(); /*实例化事件对象*/
EventEmitter.on('toparent',function(){
  console.log('接收到了广播事件');
})
setTimeout(function(){
  console.log('广播');
  EventEmitter.emit('toparent'); /*发送广播*/
},1000)


相关文章
|
7月前
|
JavaScript
Node.js【GET/POST请求、http模块、路由、创建客户端、作为中间层、文件系统模块】(二)-全面详解(学习总结---从入门到深化)
Node.js【GET/POST请求、http模块、路由、创建客户端、作为中间层、文件系统模块】(二)-全面详解(学习总结---从入门到深化)
51 0
|
7月前
|
JavaScript
Node.js【GET/POST请求、http模块、路由、创建客户端、作为中间层、文件系统模块】(二)-全面详解(学习总结---从入门到深化)(上)
Node.js【GET/POST请求、http模块、路由、创建客户端、作为中间层、文件系统模块】(二)-全面详解(学习总结---从入门到深化)
54 0
|
7月前
|
消息中间件 Web App开发 JavaScript
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
304 0
|
7月前
|
JavaScript 前端开发 API
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)(下)
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
102 0
|
1月前
|
数据采集 存储 JavaScript
如何使用Puppeteer和Node.js爬取大学招生数据:入门指南
本文介绍了如何使用Puppeteer和Node.js爬取大学招生数据,并通过代理IP提升爬取的稳定性和效率。Puppeteer作为一个强大的Node.js库,能够模拟真实浏览器访问,支持JavaScript渲染,适合复杂的爬取任务。文章详细讲解了安装Puppeteer、配置代理IP、实现爬虫代码的步骤,并提供了代码示例。此外,还给出了注意事项和优化建议,帮助读者高效地抓取和分析招生数据。
如何使用Puppeteer和Node.js爬取大学招生数据:入门指南
|
2月前
|
Web App开发 JSON JavaScript
深入浅出:Node.js后端开发入门与实践
【10月更文挑战第4天】在这个数字信息爆炸的时代,了解如何构建一个高效、稳定的后端系统对于开发者来说至关重要。本文将引导你步入Node.js的世界,通过浅显易懂的语言和逐步深入的内容组织,让你不仅理解Node.js的基本概念,还能掌握如何使用它来构建一个简单的后端服务。从安装Node.js到实现一个“Hello World”程序,再到处理HTTP请求,文章将带你一步步走进Node.js的大门。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开一扇通往后端开发新世界的大门。
|
7月前
|
消息中间件 Web App开发 JavaScript
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)(上)
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
199 0
|
4月前
|
JavaScript 前端开发 NoSQL
使用Node.js进行后端开发入门
【8月更文挑战第10天】恭喜你完成了Node.js后端开发的入门之旅!这只是个开始,Node.js的世界远比这广阔。随着你对Node.js的深入学习和实践,你将能够构建更复杂、更强大的后端应用。不断探索、学习和实践,你将在Node.js的道路上越走越远。
|
4月前
|
Web App开发 JavaScript 前端开发
Node.js 入门
【8月更文挑战第4天】Node.js 入门
66 1
|
4月前
|
JSON JavaScript 前端开发
Ctfshow web入门 nodejs篇 web334-web344
Ctfshow web入门 nodejs篇 web334-web344
76 0