NodeJS介绍和安装
什么是Node.js
- Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境(采用Google开发的V8引擎运行js代码)
- Node.js 使用了事件驱动、非阻塞式 I/O 的模型,使其轻量又高效
Node.js使用场景
- 高并发
- 即时通讯
- 推送消息
Node.js的特性
- 它是一个JavaScript运行环境
- 依赖于Chrome V8引擎
- 轻量,适于实时数据交互应用
- 单线程
- 非阻塞I/O
- 事件驱动
单线程
像java、python这个可以具有多线程的语言。多线程同步模式是这样的,将cpu分成几个线程,每个线程同步运行。Node.js不会为每个客户连接创建一个新的线程,而仅使用一个线程。也就是说每一个计算独占cpu,遇到I/O请求不阻塞后面的计算,当I/O完成后,以事件的方式通知,继续执行计算2。
非阻塞I/O
I/O(英语:Input/Output),即输入/输出,通常指数据在内部存储器和外部存储器或其他周边设备之间的输入和输出。
而在程序执行的过程中会有很多的I/O操作,如读写文件,请求响应,数据库的读写等等
非阻塞I/O也就是指程序在执行的过程中,I/O操作不会阻塞程序的执行,也就是在执行I/o操作时,程序的的执行不受影响,继续执行其他的代码(这主要得益于node的事件循环机制),很显然这种非阻塞I/O大大提高了程序的性能。
nodejs 会保证主线程不会被阻塞,如果遇到正在执行的IO操作。nodejs 会把io操作放到其他地方去执行。(通过事件驱动来执行)。系统会把这个操作挪动事件队列里面执行。执行结束的任务会以回调函数的形式,返回给线程。然后继续处理接下来的任务。
事件驱动
Nodejs 会把所有请求和异步操作都放到一个事件队列中,用户的每一个请求就是一个事件。主线程先把普通(同步任务)代码执行完毕,然后会循环事件队列里的函数,如果遇到有IO的操作,nodejs会去线程池里拿出一个线程去执行IO的操作,执行完毕后再把拿到数据的回调函数,放到事件队列的尾部,继续事件循环,当主线程再次循环到该事件时,就直接处理并返回给上层调用。 这个过程就叫 事件循环 (Event Loop)
应用层: 即 JavaScript 交互层,常见的就是 Node.js 的模块,比如 http,fs
V8引擎层: 即利用 V8 引擎来解析JavaScript 语法,进而和下层 API 交互
NodeAPI层: 为上层模块提供系统调用,一般是由 C 语言来实现,和操作系统进行交互 。
LIBUV层: 是跨平台的底层封装,实现了 事件循环、文件操作等,是 Node.js 实现异步的核心
Node.js安装
Node.js官网: https://nodejs.org/en/
Node.js中文网: http://nodejs.cn/
下载安装【傻瓜式下一步】 Current是当前最新版本 LTS是长期支持版本
查看Node.js版本: 终端 中输入 node -v
终端
通常将命令行程序称为终端
打开方式:
1.win+r 运行窗口 cmd
2.在文件夹url地址栏中输入 cmd 回车
3.在文件夹中,按shift+右键,找powershell
4.vscode 在集成终端中打开
可以在终端中通过”命令”去执行一些操作
可以用命令打开电脑中某个文件、创建某个文件夹、查看电脑的IP等等
dir 查看文件目录
cd 文件名 进入下一级
cd ../ 向上一级
cls 清屏操作
新建文件夹:
mkdir+文件夹名字,mkdir与文件名之间一定要有空格
rmdir 文件夹名字 删除文件夹
table键:补全命令
“ifconfig”:查看IP地址
tree:以树状形状显示目录结构。
盘符:进入某个磁盘 d:
运行文件
终端中输入 node 文件名
Node.js模块
- 在Node.js中,以模块为单位去划分功能
- Node.js中也提供了完整的模块加载机制
- 一个js文件就是一个模块,多个模块可以相互引用,多个模块作为整体也可看作是一个广义上的模块
- node应用由模块组成,采用的commonjs模块规范。每一个文件就是一个模块,拥有自己独立的作用域,变量,以及方法等,对其他的模块都不可见。CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。require方法用于加载模块。
- 可以有多个exports,引入只有一个require
- 也可以用来向外暴露一个类
//代码
//first.js
function say(){
console.log(obj.msg);
}
// say();
// console.log(module);
module.exports = say;
//second.js
let fir = require('./first.js');
console.log(fir);
fir();
模块的优点
减少重复代码,提高代码利用率
以功能划分,便于模块管理
方便使用第三方模块
搭建后台
http模块
- 借助http模块,通过几行代码能实现一个迷你web server
- http模块是Node.js重要的核心模块
http.Server 类:用来搭建一个服务,帮助接受请求,发送响应
http.ServerResponse 类:响应请求,设置响应的内容等
//引入http包
let http = require('http');
//http.createServer 返回http.Server实例
let serve = http.createServer(function(req,res){
// res:response 服务器的响应
// req:request 接受的前端的请求
// 设置响应头内容
res.writeHead(200,{
'content-type':'text/html;charset=utf-8',
'Access-Control-Allow-Origin':'*'
});
//res.write(); //write() 会发送一块响应主体
res.end();
//res.end(data,callback);
//此方法向服务器发出信号,表明已发送所有响应头和主体,该服务器应该视为此消息已完成,响应结束。 必须在每个响应上调用此 response.end() 方法。
//如果指定了 data,则相当于调用 response.write(data) 之后再调用 response.end(callback)。
//如果指定了 callback,则当响应流完成时将调用它
});
//serve.listen(端口号,主机名,callback)启动 HTTP 服务器用于监听连接;
url模块
url模块作用
对请求的URL进行处理和解析
也可以对URL进行格式化的操作
使用方法如下:
const url = require('url');
URL 字符串是结构化的字符串,包含多个含义不同的组成部分。 解析字符串后返回的 URL 对象,每个属性对应字符串的各个组成部分。
url模块常用API
url.parse():将一个url字符串解析并且返回一个url对象
url.format():对一个url对象进行格式化操作,返回一个url字符串
url.resolve():返回一个”from/to”的字符串,相当于对路径进行拼接
let http = require('http');
let url = require('url');
let person = [
{name:'李逵',age:18,job:'杀老虎'},
{name:'高俅',age:38,job:'踢球'},
{name:'高俅',age:38,job:'宦官'},
{name:'宋江',age:28,job:'梁山扛把子'},
{name:'西门庆',age:25,job:'不干好事'}
];
http.createServer((req,res)=>{
if(req.url === '/favicon.ico') return ;
res.writeHead(200, {
'Content-type': 'text/plain;charset=utf-8',
'Access-Control-Allow-Origin': '*'
});
// let url_obj = url.parse(req.url);
// let names = url_obj.query.split('=')[1]
// console.log(url_obj, names, decodeURI(names));
let url_obj = url.parse(req.url,true);
if('name' in url_obj.query){
let result = person.filter((item)=>{
return item.name.includes(url_obj.query.name);
});
res.write(JSON.stringify(result));
}
//WHATWG url
// let url_ = new URL(req.url,'http:127.0.0.1:2020');
// console.log(url_.searchParams.get('name'));
res.end();
}).listen(2020,'127.0.0.1',()=>{
console.log('running.......');
});
// format() 格式化一个url
let url_str = url.format({
protocol:'http',
hostname:'www.qianduan0371.com',
port:12345,
pathname:'/index/demo',
query:{
name:"lisi",
age:12
},
hash:'format_demo'
});
res.write(url_str);
//resolve
let url1 = url.resolve('/one/two/three', 'four'); // '/one/two/four'
let url2 = url.resolve('http://example.com/', '/one'); // 'http://example.com/one'
let url3 = url.resolve('http://example.com/one', '/two'); // 'http://example.com/two'
console.log(url1,url2,url3);
什么是nodejs路由
通过请求的URL路径和其他需要的 GET 及 POST 参数来区分不同的请求,随后路由需要根据这些数据来执行相应的代码(路由就可以通过这些URL路径和参数准确找到对应功能代码上)。因此,我们需要查看 HTTP 请求,从中提取出请求的 URL 以及 GET/POST 参数
//例如
http://127.0.0.1:2020/login 登录
http://127.0.0.1:2020/register 注册
案例功能:
//例如
http://127.0.0.1:2020/add 添加
http://127.0.0.1:2020/search 查询
添加用户信息(用户名、年龄)
查询用户(用户名)
接口地址:http://127.0.0.1:2020/add(search)
请求方式:get
参数:
用户名:name
年龄:age
前后端交互
fs模块
在Node.js中,对文件和文件夹进行操作,比如读取,创建等,用来管理文件的系统的模块
也可以在响应过程中读取指定的文件内容,比如html文件或者jpg文件等,并且把这些作为响应内容
fs常用API
fs.readFile():用来读取文件内容的函数
fs.readdir():读取一个文件夹的内容
fs.writeFile():文件写入内容
fs.mkdir():创建文件夹
fs.stat():检测文件状态
案例:
静态资源管理
问题:启动服务,在浏览器里无法直接查看图片,CSS等静态资源
解决方案:通过fs模块解决静态文件加载的问题
案例:
Get请求
參考nodejs路由功能
第三方模块
npm安装和使用
npm 是什么?
npm是随同Node.js一起安装的包管理工具
通过npm可以共享使用各式JS开源库,对JS开源库的版本可以直接快速的管理,使用这些基于模块开发方式让团队更好的协作开发 npm 为你和你的团队打开了连接整个 JavaScript 天才世界的一扇大门。它是世界上最大的软件注册表,每星期大约有 30 亿次的下载量,包含超过 600000 个 包(package) (即,代码模块)
更新 npm
安装node.js时,将自动安装npm。但是,npm的更新频率比Node.js的更新频率高,因此请确保您具有最新版本。
获取当前版本,请运行npm -v
。
更新到最新版本,请运行:
npm install npm@latest -g
安装模块
npm install <package name> 本地安装
npm install -g <package name> 全局安装
npm list: 查看安装信息
npm uninstall <package name>:卸载本地包
npm update <package name>:更新本地包
npm uninstall -g <package name>:卸载全局包
npm update -g <package name>:更新全局包
cnpm的安装和使用
由于npm的服务器在国外(即在“墙”外),国(墙)内开发者做项目的时候,很多“包”的下载速度极慢,在这种环境下阿里巴巴为了众多开发者的便捷便挺身而出推出了淘宝镜像(即cnpm),它把npm官方的“包”全部搬到国内,供广大开发者使用。
cnpm的官方介绍是:cnpm是一个完整 npmjs.org 镜像,你可以用此代替官方版本(只读),同步频率目前为 10分钟 一次以保证尽量与官方服务同步。
安装指令:npm install cnpm -g --registry=https://registry.npm.taobao.org
安装练习:
package.json文件详解
作用:定义了在这个项目中,需要的各种模块,以及项目的配置信息
比如名称,版本等内容,通过npm install指令,就可以通过这个文件的内容,自动下载对应模块,配置项目所需的开发环境
管理本地安装的npm软件包的最佳方法是创建一个 package.json
文件。
一个package.json
文件:
创建package.json文件
//方法1
npm init
//方法2
npm init -y(--yes)
package文件重要属性
- name:项目名或者包名
- version:版本号
- description:描述
- author:作者
- scripts:运行脚本命令的npm命令行缩写
- dependencies:项目运行所依赖的模块,一般用于生产环境(您的应用程序在生产中需要这些软件包)
- devDependencies:项目开发所需要的模块,一般用于开发环境(这些软件包仅在开发和测试时需要)
在--save
和--save-dev
安装标志
向您的依赖项中添加依赖项的更简单(更棒)方法package.json
是从命令行执行此操作,npm install
并使用--save
或 标记该命令--save-dev
,具体取决于您希望如何使用该依赖项。
要将条目添加到您package.json
的中dependencies
:
npm install <package_name> --save
要将条目添加到您package.json
的中devDependencies
:
npm install <package_name> --save-dev
指定版本:比如1.8.3
波浪号+指定版本:比如1.8.3,不低于1.8.3,安装不会改变大版本和次版本
插入号^+指定版本:比如^1.8.3,安装不改变大版本
latest:安装最新版本
package和npm配合使用
把已经配置好的package文件,通过npm进行自动安装(npm install ),完成开发环境的搭建
package-lock.json 是在 npm install
时候生成一份文件,用来记录当前状态下实际安装的各个npm package的具体来源和版本号。npm最新的版本就开始提供自动生成package-lock.json功能,为的是让开发者知道只要你保存了源文件,到一个新的机器上、或者新的下载源,只要按照这个package-lock.json所标示的具体版本下载依赖库包,就能确保所有库包与你上次安装的完全一样。
post请求
form表单POST请求
Ajax POST请求
const http = require('http');
const querystring = require('querystring');
http.createServer((req,res)=>{
if(req.url === '/favicon.ico') return;
// console.log(req);
if(req.method.toUpperCase() === 'POST'){
// 接收post 提交上来的数据
// 数据接收 分段接收。
// 会触发俩个事件
var alldata = '';
req.on('data',function(v){
alldata+=v;
});
req.on('end',function(){
alldata = querystring.parse(alldata);
console.log(alldata);
res.end(JSON.stringify(alldata));
});
}
}).listen(12345,'127.0.0.1',()=>{
console.log('running......');
})
文件上传
借助 formidable 第三方模块处理接收文件
Express框架
基于 Node.js 平台,快速、开放、极简的 Web 开发框架。
安装…
路由…
静态文件…
Express生成器…
MongoDB
什么是MongoDB ?
MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。
在高负载的情况下,添加更多的节点,可以保证服务器性能。
MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。
MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。
MongoDB 下载
你可以在mongodb官网下载该安装包,地址为:https://www.mongodb.com/download-center#community。
Windows 平台安装 MongoDB
- 完整安装
- 自定义安装
链接MongoDB
- 完整安装
- 默认安装c盘,找到MongoDB/Server/bin/ 运行mongo.exe,出现一下界面,链接成功
MongoDB 概念解析
在mongodb中基本的概念是文档、集合、数据库。
*SQL术语/概念* | *MongoDB术语/概念* | *解释/说明* |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接,MongoDB不支持 | |
primary key | primary key | 主键,MongoDB自动将_id字段设置为主键 |
通过下图实例,我们也可以更直观的了解Mongo中的一些概念:
数据库
一个mongodb中可以建立多个数据库。
MongoDB的默认数据库为”db”,该数据库存储在data目录中。
MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中。
*“show dbs”* 命令可以显示所有数据库的列表。
执行 *“db”* 命令可以显示当前数据库对象或集合。
运行”use”命令,可以连接到一个指定的数据库。
文档
文档是一组键值(key-value)对(即BSON)。****MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型****,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点。
下表列出了 RDBMS 与 MongoDB 对应的术语:
*RDBMS* | *MongoDB* |
---|---|
数据库 | 数据库 |
表格 | 集合 |
行 | 文档 |
列 | 字段 |
表联合 | 嵌入文档 |
主键 | 主键 (MongoDB 提供了 key 为 _id ) |
*数据库服务和客户端* | |
Mysqld/Oracle | mongod |
mysql/sqlplus | mongo |
集合
集合就是 MongoDB 文档组,类似于 RDBMS (关系数据库管理系统:Relational Database Management System)中的表格。
集合存在于数据库中,集合没有固定的结构,这意味着你在对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。
MongoDB 数据类型
下表为MongoDB中常用的几种数据类型。
*数据类型* | *描述* |
---|---|
String | 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。 |
Integer | 整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。 |
Boolean | 布尔值。用于存储布尔值(真/假)。 |
Double | 双精度浮点值。用于存储浮点值。 |
Min/Max keys | 将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。 |
Array | 用于将数组或列表或多个值存储为一个键。 |
Timestamp | 时间戳。记录文档修改或添加的具体时间。 |
Object | 用于内嵌文档。 |
Null | 用于创建空值。 |
Symbol | 符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。 |
Date | 日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。 |
Object ID | 对象 ID。用于创建文档的 ID。 |
Binary Data | 二进制数据。用于存储二进制数据。 |
Code | 代码类型。用于在文档中存储 JavaScript 代码。 |
Regular expression | 正则表达式类型。用于存储正则表达式。 |
MongoDB 创建数据库
MongoDB 创建数据库的语法格式如下:
use DATABASE_NAME
如果数据库不存在,则创建数据库,否则切换到指定数据库。
数据库名可以是满足以下条件的任意UTF-8字符串。
· 不能是空字符串(””)。
· 不得含有’ ‘(空格)、.、$、/、\和\0 (空字符)。
· 应全部小写。
· 最多64字节。
有一些数据库名是保留的:admin, local, config等。可以直接访问这些有特殊作用的数据库。
MongoDB 删除数据库
MongoDB 删除数据库的语法格式如下:
db.dropDatabase()
删除当前数据库,默认为 test,你可以使用 db 命令查看当前数据库名。
MongoDB 创建集合
MongoDB 中使用 *createCollection()* 方法来创建集合。
语法格式:
db.createCollection(name, options)
参数说明:
· name: 要创建的集合名称
· options: 可选参数, 指定有关内存大小及索引的选项
MongoDB 删除集合
MongoDB 中使用 drop() 方法来删除集合。
*语法格式:*
db.collection.drop()
*返回值*
如果成功删除选定集合,则 drop() 方法返回 true,否则返回 false。
以下实例删除了 runoob 数据库中的集合 site:
> use runoob
switched to db runoob
> db.createCollection("runoob") # 先创建集合,类似数据库中的表
> show tables # show collections 命令会更加准确点
runoob
> db.runoob.drop()
true
> show tables
>
插入文档
文档的数据结构和JSON基本一样。
所有存储在集合中的数据都是BSON格式。
BSON是一种类json的一种二进制形式的存储格式,简称Binary JSON。
MongoDB 使用 insert() 或 save() 方法向集合中插入文档,语法如下:
db.COLLECTION_NAME.insert(document)
以下文档可以存储在 MongoDB 的 books数据库 的 col 集合中:
db.col.insert({title: 'MongoDB 教程',
description: 'MongoDB 是一个 Nosql 数据库',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100})
MongoDB 查询文档
MongoDB 查询文档使用 find() 方法。
find() 方法以非结构化的方式来显示所有文档。
语法
MongoDB 查询数据的语法格式如下:
db.collection.find(query, projection)
MongoDB 更新文档
MongoDB 使用 *update()* 和 *save()* 方法来更新集合中的文档。
update() 方法
update() 方法用于更新已存在的文档。语法格式如下:
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
})
*参数说明:*
· *query* : update的查询条件,类似sql update查询内where后面的。
· *update* : update的对象和一些更新的操作符(如$,$inc…)等,也可以理解为sql update查询内set后面的
· *upsert* : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
· *multi* : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
· *writeConcern* :可选,抛出异常的级别。
db.col.update({‘title’:’MongoDB 教程’},{$set:{‘title’:’MongoDB’}})
以上语句只会修改第一条发现的文档,如果你要修改多条相同的文档,则需要设置 multi 参数为 true。
db.col.update({‘title’:’MongoDB 教程’},{$set:{‘title’:’MongoDB’}},{multi:true})
MongoDB 删除文档
MongoDB remove()函数是用来移除集合中的数据。
remove() 方法的基本语法格式如下所示:
db.collection.remove(<query>,{justOne: <boolean>,writeConcern: <document>})
*参数说明:*
· *query* :(可选)删除的文档的条件。
· *justOne* : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。
· *writeConcern* :(可选)抛出异常的级别。
db.col.remove({‘title’:’MongoDB 教程’}) WriteResult({ “nRemoved” : 2 }) # 删除了两条数据
>db.col.find()…… # 没有数据
如果你只想删除第一条找到的记录可以设置 justOne 为 1,如下所示:
>db.COLLECTION_NAME.remove(DELETION_CRITERIA,1)
果你想删除所有数据,可以使用以下方式(类似常规 SQL 的 truncate 命令):
>db.col.remove({})
Robo 3T 的使用…
Mongoose
mongoose模块
Node.js连接
MongoDB数据库,推荐
Mongoose`模块,可以更加方便的对数据库进行操作。
Node.js中安装模块
npm install mongoose --save
引入模块
在需要使用的js文件中引入模块。
var mongoose = require('mongoose');
连接数据库
var db = mongoose.connect('mongodb://localhost/mongodb',{
useNewUrlParser: true,
useUnifiedTopology: true
});
URL以mongodb://[用户名:密码@]数据库地址[:端口]/数据库名
。(默认端口27017)
需要对连接状况进行判断,可以用以下代码:
var db = mongoose.connection;
db.on("error", function (error) {
console.log("数据库连接失败:" + error);
});
db.on("open", function () {
console.log("数据库连接成功");
})
db.on('disconnected', function () {
console.log('数据库连接断开');
})
基本概念
最常接触到的有两个概念Schema
、Model
Schema
在 Mongoose 中,所有数据都由一个 Schema 开始创建。每一个 schema 都映射到一个 Mongodb 的集合(collection),并定义了该集合(collection)中的文档(document)的形式。但不能通过Schema对数据进行更改。
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const UserShema = new Schema({
name: { type: String, required: true },
createTime: { type: Date, default: Date.now },
sex: String,
avatar: String,
vip: Boolean,
})
Model
是将Schema定义的结构赋予集合名。可用此名对数据库进行增删查改。
Model
var blogModel = mongoose.model('集合名', 自定义Schema/UserShema);
var blogModel = mongoose.model('Blog', blogSchema);
将名为blogSchema的Schema与Blog名字绑定,即是存入集合的名字,但存入集合的名字是Blogs,会自动添加一个s。
这里将Model命名为blogModel,需要对Blog集合操作的话,都需要使用变量名blogModel。
增查改删(CRUD)
所有的参数都是以JSON对象
形式传入。
增(C)
Model.create(doc(s), [callback])
Model#save([options], [options.safe], [options.validateBeforeSave], [fn])
Model.insertMany(doc(s), [options], [callback])
查(R)
Model.find(conditions, [projection], [options], [callback])
Model.findOne([conditions], [projection], [options], [callback])
Model.findById(id, [projection], [options], [callback])
改(U)
Model.update(conditions, doc, [options], [callback])
Model.updateMany(conditions, doc, [options], [callback])
Model.updateOne(conditions, doc, [options], [callback])
删(D)
Model.remove(conditions, [callback])
Model.deleteMany(conditions, [callback])
Model.deleteOne(conditions, [callback])
相关手册
1.菜鸟教程:https://www.runoob.com/mongodb/mongodb-sort.html
2.mongoose:http://www.mongoosejs.net/docs/index.html
- 本文链接:https://wangyou.ink/2021/12/16/node/
- 版权声明:本博客所有文章除特别声明外,均默认采用 许可协议。