node.js 学习
模块化
- CommonJS----------双端(1.浏览器端;2.服务器端)------暴露:module.exports =??? exports.xxxx = ??? 浏览器不认识require ---------Browserify
- AMD--------- 只有浏览器端 ----------RequireJS-----define([‘ass’,‘dsfd’],function(){return ???})
- CMD------sea.js----借鉴,------国产的
- ESE6------前端人员主要使用的--------babel----------Browserify
Node.js是什么?
Node.js有什么特点
优点
- 异步非阻塞的I/O(I/O线程池)
2)特别适合于I/O密集型应用(对比传统java服务器)
3)事件循环机制(独有的一套,与浏览器不一样)
4)单线程(成也单线程,败也单线程)
5)跨平台(Chrome)
arguments
这是参数获取
callee 输出谁调用的
function (exports, require, module, __filename, __dirname) {
console.log(arguments.callee.toString());
}
// exports : 用于支持CommonJS模块化规范的暴露语法
// require : 用于支持CommonJS模块化规范的引用语法
// module : 用于支持CommonJS模块化规范的暴露语法
// __filename : 当前文件运行的路径,绝对的
// __dirname : 当前运行文件所在文件夹的绝对路径
// 2. 为什么要设计这个外层函数?
// 1). 用于支持模块化语法
// 2). 隐藏服务器内部实现(从作用域)
Node中的global
// 2. Node端,js有几部分组成?
/**
* 1. 没有了BOM------> 因为服务器不需要(服务端没有浏览器对象)
* 2. 没有了DOM ------> 因为没有浏览器窗口
* 3. 几乎包含了所有的ES规范
* 4. 没有了window,但是取而代之的是一个叫做global的全局变量
*/
// 3.global的一些常用属性
/*
clearInterval: 清除循环定时器
clearTimeout: 清除延时定时器
setInterval: 设置循环定时器
setTimeout: 设置延时定时器
clearImmediate: 清除立即执行函数
setImmediate: 设置立即执行函数
*/
// 禁止Node中的this指向global
Node.js 事件循环,定时器和 process.nextTick()
┌───────────────────────────┐
┌─>│ timers │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ pending callbacks │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ idle, prepare │
│ └─────────────┬─────────────┘ ┌───────────────┐
│ ┌─────────────┴─────────────┐ │ incoming: │
│ │ poll │<─────┤ connections, │
│ └─────────────┬─────────────┘ │ data, etc. │
│ ┌─────────────┴─────────────┐ └───────────────┘
│ │ check │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
└──┤ close callbacks │
└───────────────────────────┘
/*
clearInterval: 清除循环定时器
clearTimeout: 清除延时定时器
setInterval: 设置循环定时器
setTimeout: 设置延时定时器
clearImmediate: 清除立即执行函数
setImmediate: 设置立即执行函数
*/
/**
* @author: 付立翔
* @method: 这个是一个事件循环
* @param {*}
* @Date: 2021-06-19 12:00:01
* @return {*}
*/
/*
第一个阶段:timers (定时器阶段) -------------------------------------------------------------------------------------------------|
1. 开始计时 \
2. 执行定时器的回调 \
第二个阶段:pending callbacks (系统阶段) ---\ \
这个阶段不用太过关注,基本用不到 \
第三个阶段:idle,prepare (准备阶段) ---------/ \
|---------|
第四个阶段:poll (轮询阶段,核心) | 一直循环 |
----如果回调队列里有待执行的回调函数 |---------|
从回调队列中取出回调函数,同步执行(一个一个执行) |
----如果回调队列为空 |
----如果有设置过setImmediate |
进入下一个check阶段:为了执行setImmediate所设置的回调 |
----如果未设置过setImmediate |
再次阶段停留,等待回调函数被插入回调队列 |
若定时器到点了,进入下一个check阶段,原因: 为了走第五阶段,随后走第六阶段,随后第一阶段(最终目的) |
第五个阶段:check (专门用于执行setImmediate所设置的回调) |
|
第六个阶段:close callbacks (关闭回调阶段) |
|
process.nextTick()----> 用于设置立即执行函数("VIP"----能在任意阶段优先执行)------------------------------------------------------------------- |
*/
// 延时定时器--------------------------------------------------- 得出结论
setTimeout(() => {
console.log("我是setTimeout(延时定时器)"); /** 可能延时定时器会在第一阶段执行,也有可能循环一圈在执行 */
});
// 立即执行函数(回调)
setImmediate(() => {
console.log("我是setImmediate(立即执行函数)");
})
// 立即执行函数(回调) 权重最够,不过在那个阶段都优先执行
// process.nextTick(()=>{
// console.log("我是process.nextTick(立即执行函数)");
// })
/* 一旦主线程那么就延时定时器先执行 */
// 主线程----------------------------------------------------- 得出结论 因为主线程上有代码,运行需要时间,所以就会给setTimeout 定时器留出时间来进行判断和执行
console.log("我是主线程上的代码");
Buffer缓冲器
Buffer是什么?
-
Buffer是一个和数组相似的对象,不同是Buffer是专门用来保存二进制数据的.
-
它是一个[类似于数据]的m对象,用于存储数据(存储的是二进制数据).
-
Buffer的效率很高,存储和读取很快,它是直接对计算机的内存进行操作.
-
Buffer的大小一旦去定了,不可修改
-
每个元素占用内存的大小为1字节
-
Buffer是Node中的非常核心的模块,无需下载,无需引入,直接使用即可
// 类 构造函数 // 创建一个Buffer的实例------性能特别差,会清理 // let buf = Buffer(10); // console.log(buf); // 创建一个Buffer的实例------性能比New Buffer强一点,找没有人用过的 // let buf2 = Buffer.alloc(10); // console.log(buf2); // 创建一个Buffer的实例------性能最好的,但是不安全,不会清理,不会去找没有人用过的 /** * 1. 输出的Buffer里有大于1的? * 2. 输出的Buffer 不为空? */ // let buf3 = Buffer.allocUnsafe(10); // console.log(buf3); // 将数据存入一个Buffer实例 let buf4 = Buffer.from('hello atguigu'); console.log(buf4.toString()); /** * 1. 输出为什么不是我们曾经存入的字符串?用户存储的不一定是字符串,可能是媒体类型的文件 * * 2. 如何能够让输出的东西是字符串(我们能看懂的)?toString(); */
-
文件写入
简单的文件写入
流式文件写入
// 只要用到了流就必须监视流的状态
let ws = createWriteStream(__dirname + '/demo.txt');
ws.on('open', function () {
console.log('流打开了');
});
ws.write('傻逼\t');
ws.close(); // 使用方法关闭数据丢失
ws.end();
ws.on('close', function () {
console.log('流关闭了');
})
流文件读取
–options:
–flags
–encoding
–fd
–mode
–autoCLose
–emitCLose
–start : 起始
–end : 结束偏移量
–highWaterMark: 每次读取数据的大小 1024
数据库操作
-
关系型数据库
mysql.Oracle.DB2.SQL Server
-
优点:
易于维护,
使用方便
高级查询
-
缺点:
读写性能比较差,尤其是海量数据的高效率读写;
有固定的表结构,字段不可随意更改,灵活度稍欠
高并发读写需求,传统关系型数据库来说,硬盘I/O是一个很大的瓶颈
-
-
非关系型数据库
mogodb,Redis
特点:关系不紧密,有文档,有键值对
Redis特点:高速缓存
-
优点
格式灵活
速度快:使用内存做为载体
易用
-
安装mongodb
下载完配置环境变量,
在c盘新建data/db文件夹
新建data/log
mongod.cfg
systemLog:
destination: file
path: c:\data\log\mongod.log
storage:
dbPath: c:\data\db
net:
port: 27017
cmd
sc.exe create MongoDB binPath= "\"E:\MongoDB\bin\mongod.exe\" --service --config=\"E:\MongoDB\mongod.cfg\"" DisplayName= "MongoDB" start= "auto"
sc delete 服务名
MongoDB 基本命令
MongoDB原生CRUD(增删改查)命令总结
-C creat:
db.集合名.insert(文档对象)
db.集合名.insertOne(文档对象)
db.集合名.insertMany([文档对象,文档对象])
-R read:
db.集合名.find(查询条件[,投影])
举例:db.students.find({age:18}),查找年龄为18的所有信息
举例:db.students.find({age:18,name:'jack'}),查找年龄为18且名字为jack的学生
常用操作符:
1. < , <= , > , >= , !== 对应为: $lt $lte $gt $gte $ne
举例:db.集合名.find({age:{$gte:20}}),年龄是大于等于20的
2.逻辑或:使用$in 或 $or
查找年龄为18或20的学生
举例:db.students.find({age:{$in:[18,20]}})
举例:db.students.find({$or:[{age:18},{age:20}]})
3.逻辑非:$nin
4.正则匹配:
举例:db.students.find({name:/^T/})
5.$where能写函数:
db.students.find({$where:function(){
return this.name === 'zhangsan' && this.age === 18
}})
投影:过滤掉不想要的数据,只保留想要展示的数据
举例:db.students.find({},{_id:0,name:0}),过滤掉id和name
举例:db.students.find({},{age:1}),只保留age
补充:db.集合名.findOne(查询条件[,投影]),默认只要找到一个
-U update:
db.集合名.update(查询条件,要更新的内容[,配置对象])
//如下会将更新内容替换掉整个文档对象,但_id不受影响
举例:db.students.update({name:'zhangsan'},{age:19})
//使用$set修改指定内容,其他数据不变,不过只能匹配一个zhangsan
举例:db.students.update({name:'zhangsan'},{$set:{age:19}})
//修改多个文档对象,匹配多个zhangsan,把所有zhangsan的年龄都替换为19
举例:db.students.update({name:'zhangsan'},{$set:{age:19}},{multi:true})
补充:db.集合名.updateOne(查询条件,要更新的内容[,配置对象])
db.集合名.updateMany(查询条件,要更新的内容[,配置对象])
-D delete
db.集合名.remove(查询条件)
//删除所有年龄小于等于19的学生
举例:db.students.remove({age:{$lte:19}})
模块化数据库操作
有一个db专门连接数据库
let mongoose = require('mongoose');
mongoose.set('useCreateIndex', true); // 使用一个新的索引创建器
// 1. 连接数据库
mongoose.connect('mongodb://127.0.0.1:27017/dd', {
useNewUrlParser: true, // 使用一个新的url解析器,用于解决一些安全性问题
useUnifiedTopology: true // 使用一个统一的新的拓扑结构
});
let isConnect = new Promise((resolve, reject) => {
// 2. 绑定数据库连接的监听
mongoose.connection.on('open', function (err) {
if (err) {
reject(err);
}
resolve(true);
// 3. 操作数据库
})
})
module.exports = isConnect
表模型
// 连接数据库,借助第三方工具库
let mongoose = require('mongoose')
let Schema = mongoose.Schema; // ----- 引入模式对象
let studentRule = new Schema({
stu_id: {
type: String, // 限制学号必须为字符串
required: true, // 限制学号为必填项
unique: true, // 限制学号唯一
},
name: {
type: String, // 限制学号必须为字符串
required: true, // 限制学号为必填项
},
age: {
type: Number, // 限制学号必须为字符串
required: true, // 限制学号为必填项
},
sex: {
type: String, // 限制学号必须为字符串
required: true, // 限制学号为必填项
},
hobby: [String],
info: Schema.Types.Mixed,
date: {
type: Date,
default: Date.now(),
},
enable_flag: {
type: String,
default: "Y"
}
}); // 创建约束对象
module.exports = mongoose.model('student', studentRule); // 用于生成某个集合所对应的模型对象 创建模型对象
增删改查
// 连接数据库,借助第三方工具库
let mongoose = require('mongoose')
// 引入学生模型
let stuModel = require('./model/studentModel')
let db = require('./model/db')
// 判断如果成功,crud
db.then((data) => {
stuModel.find({ name: "傻逼" }, function (err, data) {
if (err) {
console.log(err);
return;
}
console.log(data);
})
}, (err) => {
console.log(err);
});
Node原生搭建服务器
// 创建一个http
// 引入Node内置的http模块
let http = require('http')
let querystring = require('querystring')
// 创建一个服务员 ------- 创建服务对象
let server = http.createServer(function (req, res) {
let index = req.url.indexOf('?');
let par = req.url.substr(index + 1);
console.log(querystring.parse(par));
res.setHeader('content-type', 'text/html;charset=utf8')
res.end("大傻逼");
})
// 让服务员开始干活,获取客人点的菜单
server.listen(8083, function (err) {
!err ? console.log("端口打开", 'http://127.0.0.1:8083') : console.log(err);
})
express框架
1. 下载
yarn add express
2. GET请求
GET http://localhost:3000/index.html?username=sunwukong&password=123123 HTTP/1.1Host: localhost:3000Connection: keep-alivePragma: no-cacheCache-Control: no-cacheUpgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8Accept-Encoding: gzip, deflate, brAccept-Language: zh-CN,zh;q=0.9
-
GET http://localhost:3000/hello.html HTTP/1.1:GET请求,请求服务器路径为http://localhost:3000/hello.html,?后面跟着的是请求参数(查询字符串),协议是HTTP 1.1版本
-
Host: localhost:3000:请求的主机名为localhost,端口号3000
-
Connection: keep-alive:处理完这次请求后继续保持连接,默认为3000ms
-
Pragma: no-cache:不缓存该资源,http 1.0的规定
-
Cache-Control: no-cache: 不缓存该资源 http 1.1的规定,优先级更高
-
Upgrade-Insecure-Requests: 1:告诉服务器,支持发请求的时候不用http而用https
-
User-Agent: Mozilla/5.0 (…:与浏览器和OS相关的信息。有些网站会显示用户的系统版本和浏览器版本信息,这都是通过获取User-Agent头信息而来的
-
Accept: text/html,…:告诉服务器,当前客户端可以接收的文档类型。q 相当于描述了客户端对于某种媒体类型的喜好系数,该值的范围是 0-1。默认为1
-
Accept-Encoding: gzip, deflate, br:支持的压缩格式。数据在网络上传递时,可能服务器会把数据压缩后再发送
-
Accept-Language: zh-CN,zh;q=0.9:当前客户端支持的语言,可以在浏览器的工具选项中找到语言相关信息
3. POST请求
lPOST请求要求将form标签的method的属性设置为post
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0USlmfJf-1632482418668)(file:///C:\Users\21727\AppData\Local\Temp\ksohtml7104\wps1.jpg)]
lPOST请求是可以有请求体的,而GET请求没有请求体
POST http://localhost:3000/index.html HTTP/1.1Host: localhost:3000Connection: keep-aliveContent-Length: 34Pragma: no-cacheCache-Control: no-cacheOrigin: http://localhost:3000Upgrade-Insecure-Requests: 1Content-Type: application/x-www-form-urlencodedUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8Referer: http://localhost:3000/form.htmlAccept-Encoding: gzip, deflate, brAccept-Language: zh-CN,zh;q=0.9Cookie: Webstorm-129da853=8726c2d8-3b88-48b8-8db0-dd82e62fb79a username=sunwukong&password=123123
-
Origin: http://localhost:3000:请求来源于 http://localhost:3000
-
Content-Type: application/x-www-form-urlencoded:提交数据的方式
-
Cookie: Webstorm…:cookie信息
-
username=sunwukong&password=123123:请求体内容!对应form表单输入的内容
1.3.3 响应报文
1. 报文格式
响应首行;响应头信息;空行;响应体;
2. 报文分析
HTTP/1.1 200 OKX-Powered-By: ExpressAccept-Ranges: bytesCache-Control: public, max-age=0Last-Modified: Wed, 21 Mar 2018 13:13:13 GMTETag: W/"a9-16248b12b64"Content-Type: text/html; charset=UTF-8Content-Length: 169Date: Thu, 22 Mar 2018 12:58:41 GMTConnection: keep-alive <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title></head><body> <h1>这是我的第一个服务器</h1></body></html>
-
HTTP/1.1 200 OK:协议是HTTP 1.1版本,请求响应成功
-
X-Powered-By: Express:自定义的头,表示用的框架,一般不返回容易造成安全漏洞。
-
Accept-Ranges: bytes:告诉浏览器支持多线程下载
-
Cache-Control: public, max-age=0:强制对所有静态资产进行缓存,即使它通常不可缓存。max-age指定多久缓存一次
-
Last-Modified: Wed, 21 Mar 2018 13:13:13 GMT:这个资源最后一次被修改的日期和时间
-
ETag: W/“a9-16248b12b64”:请求资源的标记/ID
-
Content-Type: text/html; charset=UTF-8:返回响应体资源类型
-
Content-Length: 169:响应体的长度
-
Date: Thu, 22 Mar 2018 12:58:41 GMT:提供了日期的时间标志,说明响应报文是什么时间创建的
3. 响应状态码
响应码对浏览器来说很重要,它告诉浏览器响应的结果。
-
200:请求成功,浏览器会把响应体内容(通常是html)显示在浏览器中;
-
301:重定向,被请求的旧资源永久移除了(不可以访问了),将会跳转到一个新资源,搜索引擎在抓取新内容的同时也将旧的网址替换为重定向之后的网址;
-
302:重定向,被请求的旧资源还在(仍然可以访问),但会临时跳转到一个新资源,搜索引擎会抓取新的内容而保存旧的网址;
-
304:请求资源未被修改,浏览器将会读取缓存;
-
404:请求的资源没有找到,说明客户端错误的请求了不存在的资源;
-
500:请求资源找到了,但服务器内部出现了错误;
1.4 get和post区别
-
GET使用URL或Cookie传参,而POST将数据放在BODY中。
-
GET方式提交的数据有长度限制,则POST的数据则可以非常大。
-
POST比GET相对安全,因为数据在地址栏上不可见。
1.4.1 常见的get请求
-
url地址栏发送请求
-
点击a标签发送请求
-
Form表单没有填写(method: post)时发送的请求
1.4.2 常见的post请求
- Form表单method: post时发送的请求