web前端2021–小白进阶之路Node.js
ES6新特征
- 块级作用域
let声明的变量不存在提升,不允许反复声明
在块级作用域下使用let声明的变量是局部变量,不能被其他作用域访问
注意:if,else,while,for…所有大括号中都是块级作用域
//练习:使用let声明变量,计算1~100之间所有整数的和
//循环作用域,同样属于块级作用域
let sum=0;
for(let i=1;i<=100;i++){
//此时i是局部变量,避免了对全局的污染
sum+=i;
}
console.log(sum);
- 函数增强
可以给形参设置默认值,如果调用函数的时候,不提供实参,则使用默认值
function add(a,b,c=0){
console.log(a+b+c);
}
add(4,5);
- 箭头函数
简化了匿名函数的写法,但不等价于匿名函数
sort((a,b)=>{
return a-b;
})
//再简化:当箭头函数的函数体只有一行代码时,并且是return形式
sort((a,b)=>a,b)
- 模板字符串
`这就是模板字符串,可以写任意的字符不需要拼接${js表达式}`
Node.js简述
Node.js运行在服务器端的js解释器,基于谷歌V8引擎解释器
可以实现服务端操作,例如数据库操作,web服务器的创建
-
对比JS和Node.js的区别
· JS运行在客户端浏览器,Node.js运行在服务器端
· JS存在多款浏览器,代码有兼容性问题,Node.js只有一个解释器,代码不存在兼容性问题
· 两者都有自定义对象和内置对象,不同的宿主对象
· JS用于浏览器端的交互效果,Node.js用于服务器端操作,数据库操作,web服务器创建等 -
官方网站
nodejs.org nodejs.cn(中文镜像) -
执行方式
脚本模式:node c:/xammp/…/02.js 回车
交互模式:node 回车 进入交互模式
退出交互模式:两次ctrl+c 或者 .exit 回车 -
应用场景
属于I/O密集型,可以解决数万个并发连接,适合做基于社交网络的大规模web应用
全局对象
在交互模式下,创建的函数和声明的变量都是全局下的,可以使用global访问——global.a global.fn()
在脚本模式下,创建的函数和声明的变量都不是全局下的,都是局部的
在JS下,创建的函数和声明的变量都是全局下的,可以使用全局对象window来访问——window.fn()
console对象
- console.log();//输出日志
- console.info();//输出消息
- console.warn();//输出警告
- console.error();//输出错误
- console.time(’ ');//开始计时
- console.timeEnd(’ ');//结束计时
开始和结束计时打印的内容要保持一致
//练习:查看循环一万次,for循环,while循环,do-while循环的耗时情况
console.time('a');
let i=1;
while(i<=10000){
i++;
}
console.timeEnd('a');
console.time('b');
i=1;
do{
i++;
}while(i<=10000);
console.timeEnd('b');
process对象
- process表示进程的对象
- process.arch 查看CPU架构
- process.platform 查看当前的操作系统
- process.version 查看当前node.js版本号
- process.env 查看当前环境变量有哪些
- process.kill(编号) 结束指定编号的进程
环境变量 如果把一个外部的软件加到环境变量里面就可以在系统里应用了
Buffer对象
- 缓冲区:在内存中临时存储数据的区域,通常网络传输的数据都是在缓冲区。
- 创建Buffer:
let buf=Buffer.alloc(5,'abcde');
- 转为字符串
buf.toString() String(buf)
//一个中文占3个字节
let buf=Buffer.alloc(15,'一二三四五');
console.log(buf);
//将buffer数据转为字符串
console.log(String(buf),buf.toString);
模块
模块:一个独立的功能体
在Node.js下规定,任意一个文件就是一个模块
分为自定义模块,核心模块,第三方模块
Node.js自动为每个文件添加了一个构造函数
(function(exports,require,module,_filename,_dirname){码农们自己的代码~})
require:是一个函数,用于引入另一个模块
exports:是导出的对象,如果要导出内容,都是向这个对象中添加
模块分类
07_yan.js
console.log('这是然哥的眼睛');
var b=3;
function add(a,b){
return a+b;
}
//默认当前模块导出的对象为空对象,如果要导出内容,需要往导出对象中添加内容
//exports={}; 就是导出对象
//导出内容:就是往导出对象中添加内容
exports.num=1;
exports.b=b;
exports.add=add;
var person={};
person.name='range';
07_tou.js
let yan=require('./07_yan.js');
console.log(yan);
console.log(yan.b);
console.log( yan.add(2,3) );
练习:
在03_1.js模块中引入03_2目录,目录下包含文件index.js,文件中导出一个函数,计算任意两个数字相加的和;在03_1.js下调用该函数。
模块中的参数
- require 是一个函数,用于引入其它的模块
- module 当前模块的对象
- module.exports 当前模块导出的对象
- exports 导出对象的别名,默认和module.exports指向同一个对象
- __filename 当前模块的绝对路径和文件名称
- __dirname 当前模块的绝对路径
//两个模块内的变量 全局变量
console.log(__filename);//文件名称:绝对路径+文件名称
console.log(__dirname);//目录名称:绝对路径
如果要导出对象,需要吧要导出的对象赋值给module.exports,此时module.exports就不再指向同一个对象了。
包和npm
包:第三方模块,一个包就是一个目录模块
npm:用于管理包的工具,包括下载安装,写在,更新,上传等。
-
命令行切换目录
cd 绝对目录 回车
如果涉及到盘符变化,需要
盘符名称: 回车 -
使用npm
npm -v //查看当前版本号
npm install 包名称, //下载安装包,自动到node_modules中,同时产生package-lock.json文件,用于锁定版本号 会依赖记录包的信息
npm config set registry https://registry.npm.taobao.org/
设置npm下载地址,从国内镜像下载
package-lock.json和node_modules是第三方包的位置
package-json包说明信息(包的说明书)
package-lock.json锁定版本号(所依赖包的信息) -
CommonJS规范
JS向服务器发展遵循了这个规范,例如模块中引入,导出,作用域都是这个规范的实现。
查询字符串
查询字符串:浏览器向服务器传递数据的一种方式,位于URL中
- parse() 将查询字符串解析成对象
- stringify() 将对象格式化为查询字符串
练习:
//练习:获取以下URL中的数据
//https://www.tmooc.cn:443/admin.html?uname=root&upwd=123;
let str1='https://www.tmooc.cn:443/admin.html?uname=root&upwd=123;';
//解析URL对象
let obj1=url.parse(str1);
console.log(obj1);
//解析查询字符串对象
let str2=obj1.query;
let obj2=querystring.parse(str2);
console.log(obj2);
URL模块
用来处理和解析URL的
http://www.codeboy.com:80/product.html?lid=5
协议 域名/IP地址 端口 文件路径 查询字符串
定时器
- 一次性定时器
开启
let timer=setTimeout(回调函数, 间隔时间)
当间隔时间到了执行一次回调函数,时间单位是毫秒
清除
clearTimeout(timer)
- 周期性定时器
开启
let timer=setInterval( 回调函数, 间隔时间 );
每隔一段时间,执行一次回调函数
清除
clearInterval(timer)
- 立即执行定时器
开启
let timer=setImmediate(回调函数)
清除
clearImmediate(timer)
在事件队列开头执行
process.nextTick(回调函数)
在主程序后执行
//一次性定时器
//开启
//3秒钟以后执行前边的回调函数
let timer=setTimeout( function(){
console.log('然哥该起床了');
},3000 );
//清除
clearTimeout(timer);
//周期性定时器
let timer=setInterval( ()=>{
console.log('然哥该起床了');
},3000 );
//清除
clearInterval(timer);
//立即执行定时器
//没有间隔时间
let timer=setImmediate( function(){
console.log(1);
} );
//清除
//clearImmediate(timer);
//另一个立即执行定时器
process.nextTick( function(){
console.log(3);
} );
console.log(2);
文件系统模块
- 查看文件状态
fs.stat(path,callpack) / fs.statSync
path 文件路径
callback 用于获取结果
err 可能产生的错误结果
stats 文件的具体状态
同步和异步
同步:会阻止后续代码的执行,只有前边的代码执行完才能执行后边的
异步:不会阻止后续代码的执行,后边代码可以先执行,通常是通过回调函数获取结果
fs模块
-
创建目录
fs.mkdir(path,callback)/fs.mkdirSync(path)
path 目录路径
callback 回调函数 -
读取目录
fs.readdir(path, callback) / fs.readdirSync(path)
-
移除目录
fs.rmdir(path, callback) / fs.rmdirSync(path
-
覆盖写入文件
fs.writeFile(path, data, callback) / fs.writeFileSync(path, data)
path 文件的路径
data 要写入的数据
如果文件不存在,会先创建文件然后写入数据
如果文件已经存在,会覆盖其中的内容写入数据 -
追加写入
fs.appendFile(path, data, callback) / fs.appendFileSync(path, data)
如果文件不存在,会先创建文件然后写入数据
如果文件已经存在,会在文件的末尾追加写入数据 -
读取文件
fs.readFile(path, callback) / fs.readFileSync(path)
读取的数据格式为Buffer,需要转字符串。 -
删除文件
fs.unlink(path, callback) / fs.unlinkSync(path)
-
检测文件
fs.existsSync(path)
流(stream)
数据流,只需要内存中很小空间,就可以读取一个大文件
- 创建可读取的流对象:
fs.createReadStream(path)
- 创建可写入的流对象:
fs.createWriteStream(path)
- 管道(专门用于处理流):
pipe()
(详见文件03_stream.js)
const fs=require('fs');
/*
//文件流
//创建一个可读取的文件流对象
let readStream=fs.createReadStream('XAMPP.zip');
//获取数据
//通过实践:一旦有数据进来,自动获取
//on('data') 监听是否有数据流,data是固定写法,就是事件的名称;
//通过回调函数获取数据
let i=0;
readStream.on('data',function(chunk){
//chunk 就是所读取的数据,分段的数据
//console.log(chunk);
//每读取一段加1
i++;
});
//事件:监听是否读取结束
//end是事件名称,固定写入:如果结束会自动触发该事件,执行后边的回调函数
readStream.on('end',function(){
console.log('读取结束',i);
});
*/
//使用流完成拷贝大文件
//创建一个可读取的流
const readStream=fs.createReadStream('XAMPP.zip');
//创建可写入的流
const writeStream=fs.createWriteStream('range.rar');
//把读取的流通过管道添加到写入流
//pipe 管道
readStream.pipe(writeStream);
http协议
- 通用头信息(General)通用的响应+请求
1)Request URL:请求的URL,代表请求的内容是哪些
2)Request Method: 请求的方法,请求内容的方式,常用的get(从对方获取) post(把东西给对方)
3)StatusCode:响应的状态码
1**:正在响应,还没有结束
2**:成功的响应
3**:响应的重定向,会跳转到另一个URL,要结合响应头信息的Localtion完成跳转
4**:客户端错误
5**:服务端错误
const http=require('http');
//请求其他服务器
//get请求方法
//参数1:请求的URL
//参数2:通过回调函数获取服务器端的响应
http.get('http://www.weather.com.cn/data/sk/101030100.html',function(res){
//res响应的对象
//获取响应的状态码
console.log(res.statusCode);
//获取数据(流)
//监听是否有数据流
res.on('data',function(chunk){
//chunk传递的数据,分段的
console.log(chunk.toString() );
});
});
- 响应头信息
1)Location: 跳转到另一个URL,结合状态码3**
2)Content-Length: 响应的内容的长度
3)Accept-Ranges: 响应内容的单位 通常是bytes
4)Content-Type: 响应的文件类型 - 请求头信息
Accept-Encoding: 浏览器接受的压缩类型 gzip / deflate - 请求的主体
传递的数据,可有可无
express框架
基于Node.js平台的,快速,开放,极简的web开发框架
下载安装express框架:npm install express
创建web服务器
const express=require('express');
const app=express();
app.listen(8080);
传数据
app.get('/url',function(req,res){
res.on('data',function(chunk){
let obj=querystring.parse(chunk.toString( ) );
console.log(obj);
});
res.sendFile(__dirname+'/myweb.html');
res.redirect('http://www.tmooc.cn');
res.send('<h2>这是登录的网页</h2>');
});
- 路由
浏览器向web服务器发送请求,web服务器根据特定请求的URL和请求的方法做出的响应
res 响应对象
res.send() 设置响应内容并发送
res.redirect() 响应的重定向,会跳转到另一个URL
req 请求对象
req.method 请求的方法
req.url 请求的URL
req.query 获取查询字符串传递的数据,并解析为对象
req.params 获取路由传参的数据,并解析为对象
路由器
在项目开发中,可能出现团队协作,无法每人负责一个模块独立开发;
不同模块之间可能出现相同的URL的所有路由单独的写到一个文件下即路由器下,给URL添加统一的前缀。
练习:
//创建路由器,并导出路由器对象
//引入express
const express=require('express');
//创建路由器对象
const router=express.Router();
//往路由器对象中添加路由
//get /list
router.get('/list',function(req,res){
res.send('这是商品列表');
});
//导出路由器对象
module.exports=router;
//创建web服务器,将路由器挂载到服务器下,添加前缀/product
const express=require('express');
//引入路由器
const productRouter=require('./product.js');
//console.log(productRouter);
const app=express();
app.listen(8080);
//把路由器挂载到服务器下,同时添加前缀/product
app.use('/product', productRouter);
中间件
浏览器向服务器发送请求,中间件拦截请求并作出响应;中间件最终为路由服务。
分为应用级中间件,路由级中间件,内置中间件,第三方中间件,错误处理中间件。
- 应用级中间件(自定义中间件)
应用级中间件又称自定义中间件,本质是一个函数。
app.use(URL,callback);
- 路由级中间件
路由器的使用 - 内置中间件
express中,当前只有一个内置中间件。
托管静态资源:服务器把所有的静态资源(html,js,css等)托管到指定的目录下,如果浏览器端要请求文件,不需要再创建路由,自动的到该目录下查找。
app.use(express.static('目录名称'));
- 第三方中间件使用
第三方中间件都是以第三方模块的形式出现,需要先下载安装。
通常express在下载安装的时候会附带下载一些第三方中间件。
body-parse中间件的使用
//1.引入中间件
const bodyParser=require('body-parser');
//2.使用中间件(在路由之前) app.use(bodyParser.urlencoded({ extended:false }));
//不使用第三方的qs模块解析为对象,而是使用querystring这个核心模块
//3.在路由中获取数据,格式为对象 req.body
mysql模块
-
连接数据库:
完整:mysql -h127.0.0.1 -P3306 -uroot -p
简写:mysql -uroot
mysql -uroot<D:\web TN2002…\xz.sql -
回顾mysql的增删改查:
增:INSERT INTO emp VALUES( );
删:DELETE FROM emp WHERE eid=5;
改:UPDATE emp SET phone=’…’,sex=0/1 WHERE eid=5;
查:SELECT * FROM emp; -
使用步骤:
①下载安装mysql第三方模块 npm install mysql
②使用mysql模块连接mysql数据库
mysql.createConnection() 普通连接
******* mysql.createPool() 连接池(推荐写法)********
③执行SQL语句
pool.query(sql,arr,callback)
·sql 要执行的SQL语句
·arr 要过滤的数据,会替换SQL语句中占位符(?)
·callback 回调函数,用于获取SQL语句的结果
err可能出现的错误
result SQL语句的结果 -
SQL注入:
查询是否登录成功,到数据库查询有没有用户名和密码同时匹配的数据,如果有登录成功
SELECT * FROM user WHERE uname=‘root’ AND upwd=‘123456’ OR 1=1;
SELECT * FROM emp WHERE eid=‘5’ OR 1=1;