node基于chrome的v8引擎的运行环境
下载安装node.js
LTS是 稳定版
Current是 实验板
模块化
module.exports和exports是一样的地址引用关系
但是已module.exports为准
第一种方式
const add = (n1,n2)=>n1+n2;
const num = 123;
exports.add = add;
exports.num = num;
const something = require('./xxx')
something.add(10,20)
something.add(something.num,50)
第二种方式
const greething = name => `hello${name}`;
module.exports.greething = greething;
const a = require('./module');
console.log(a.greething('李四'));
系统模块 node为错误优先
fs模块 文件操作
const fs = require('fs')
读取
fs.readFile('路径',['编码'],callback)
fs.readFile('./module.js','utf-8',(err,res)=>{
console.log(err);
console.log(res);
})
写入 使用场景为错误日志 如果没有目标文件则会创建
fs.writeFile('文件路径','数据',callback)
const str = `<h2>写入的数据</h2>`
fs.writeFile('./test.html', str, err => {
if (err != null) {
console.log(err);
return
}
console.log("写入成功");
})
path模块 路径操作
windows 正斜杠反斜杠都可以的
Windows \ /
Linux /
path.join('路径','路径',...)
const path = require('path')
let testPath = path.join("public","uploads","avatar")
绝对路径相对路径 __dirname
__dirname拿到当前目录的绝对路径
__dirname拿到当前目录的绝对路径
const path = require('path')
const fs = require('fs')
fs.readFile(path.join(__dirname,"index.js"), 'utf-8', (err, res) => {
console.log("我是err",err);
console.log("我是res",res);
})
console.log("我是pathjoin的结果",path.join(__dirname,"index.js"));
console.log("我是当前绝对路径",__dirname);
模块 全局安装 本地安装 nodemon nrm换源
npm install axios
npm uninstall axios
一般命令行会用全局安装
npm install nodemon -g
nodemon index.js
npm install nrm -g
查询 nrm ls
切换 nrm use 下载地址名称
开发依赖 项目依赖 命令别名
gulp不需要在项目依赖里所以下载时
npm i gulp --save-dev
开发环境 npm i 会下载所有依赖
运行依赖 npm i --production 只下载生产环境
命令别名
在scripts里新建
"别名" : "原名"
网站服务器 http协议
搭建基础
//引用系统模块 用于创建网站服务器的模块
const http = require('http');
//http.createServer()返回值为网站服务器对象
const app = http.createServer();
//事件驱动 所以添加事件 res == response响应
app.on('request',(req,res)=>{
res.end('<h2>hello user</h2>')
})
app.listen(3000)
console.log("网站服务器启动成功");
判断不同的请求方式req.method
后台
//引用系统模块 用于创建网站服务器的模块
const http = require('http');
//http.createServer()返回值为网站服务器对象
const app = http.createServer();
//事件驱动 所以添加事件 res == response响应
app.on('request', (req, res) => {
//获取前台的请求方式
console.log(req.method);
res.end('<h2>hello user</h2>')
})
app.listen(3000)
console.log("网站服务器启动成功");
前台
<body>
<form method="POST" action="http://localhost:3000">
<input type="submit">
</form>
</body>
判断
//引用系统模块 用于创建网站服务器的模块
const http = require('http');
//http.createServer()返回值为网站服务器对象
const app = http.createServer();
//事件驱动 所以添加事件 res == response响应
app.on('request', (req, res) => {
//获取前台的请求方式
console.log(req.method);
if(req.method == "POST"){
res.end("post")
}else if(req.method == "GET"){
res.end("get")
}
// res.end('<h2>hello user</h2>')
})
app.listen(3000)
console.log("网站服务器启动成功");
判断不同的请求地址req.url 需用url.parse处理
请求什么都不写那么就是 /
let {query,pathname} = url.parse(req.url,true)
//引用系统模块 用于创建网站服务器的模块
const http = require('http');
//http.createServer()返回值为网站服务器对象
const app = http.createServer();
//事件驱动 所以添加事件 res == response响应
app.on('request', (req, res) => {
//获取前台的请求地址
console.log(req.url);
这里获取的是带get请求参数的请求地址
所以需要用url模块进行处理
if(req.url == "/index" || req.url == "/"){
res.end("welcome to homepage")
}else if(req.url == "/list"){
res.end("welcome to list")
}else{
res.end("not found")
}
res.end('<h2>hello user</h2>')
})
app.listen(3000)
console.log("网站服务器启动成功");
请求报文 响应报文 状态码 end内容类型
console.log(req.headers);
console.log(req.headers["accept"]);
状态码
200请求成功
404请求的资源没有被找到
500服务器端错误
400客户端请求有语法错误
const http = require('http');
const app = http.createServer();
app.on('request', (req, res) => {
res.writeHead(200) //这里设置返回码
if(req.url == "/index" || req.url == "/"){
res.end("welcome to homepage")
}else if(req.url == "/list"){
res.end("welcome to list")
}else{
res.end("not found")
}
})
app.listen(3000)
console.log("网站服务器启动成功");
内容类型
test/html
text/css
text/plain 纯文本
application/javascript
image/jpeg
application/json
const http = require('http');
const app = http.createServer();
app.on('request', (req, res) => {
res.writeHead(200,{
"content-type":"text/html;charset=utf-8", //设置请求头
})
console.log(req.headers["accept"]);
//获取前台的请求地址
console.log(req.url);
if(req.url == "/index" || req.url == "/"){
res.end("<h1>你好</h1>")
}else if(req.url == "/list"){
res.end("welcome to list")
}else{
res.end("not found")
}
})
app.listen(3000)
console.log("网站服务器启动成功");
请求参数
GET请求参数
提供了一个内置模块 用于处理url地址
const url = require('url')
url.parse(req.url) //会把链接返回成一个对象 处理数据
Url {
protocol: null,
slashes: null,
auth: null,
host: null,
port: null,
hostname: null,
hash: null,
search: '?name=zhangsan$age=20',
query: 'name=zhangsan$age=20',
pathname: '/index',
path: '/index?name=zhangsan$age=20',
href: '/index?name=zhangsan$age=20'
}
//第一个参数要解析的url地址
//第二个参数将查询参数解析成对象形式
url.parse(req.url,true)
Url {
protocol: null,
slashes: null,
auth: null,
host: null,
port: null,
hostname: null,
hash: null,
search: '?name=zhangsan&age=20',
query: [Object: null prototype] { name: 'zhangsan', age: '20' },
pathname: '/index',
path: '/index?name=zhangsan&age=20',
href: '/index?name=zhangsan&age=20'
}
所以
//获取前台的请求地址
console.log(req.url);
//前台的请求参数
console.log(url.parse(req.url,true).query);
解构写法
const http = require('http');
const app = http.createServer();
const url = require('url')
app.on('request', (req, res) => {
res.writeHead(200,{
"content-type":"text/html;charset=utf-8",
})
//获取前台的请求地址
console.log(req.url);
let {query,pathname} = url.parse(req.url,true)
console.log(query);
console.log(pathname);
if(pathname == "/index" || pathname == "/"){
res.end("<h1>你好</h1>")
}else if(pathname == "/list"){
res.end("welcome to list")
}else{
res.end("not found")
}
})
app.listen(3000)
console.log("网站服务器启动成功");
POST请求参数
const http = require('http');
const app = http.createServer();
//处理请求参数数据 而不是链接+参数数据
const querystring = require('querystring')
app.on('request', (req, res) => {
//post参数是通过事件的方式接受的
//data 传递时
//end 传递完成
//post不是一下传递的是分好几次接收的
let postParams = "";
req.on('data',(params)=>{ //post不是一下传递的是分好几次接收的
postParams += params //这里做拼接
})
req.on('end',()=>{
有一个系统模块转换 接受的值querystring
console.log(querystring.parse(postParams)); //这里返回的就是对象了
})
//要做出响应否则会处于等待状态
res.end("ok")
})
app.listen(3000)
console.log("网站服务器启动成功");
end一些api
重定向 转跳
res.write(301,{
location:"/list"
})
res.end()
路由
const http = require('http');
const app = http.createServer();
const url = require('url')
app.on("request",(req,res)=>{
//请求方式
const method = req.method.toLowerCase();
//请求地址
const pathname = url.parse(req.url).pathname;
//报文设置
res.writeHead(200,{
"content-type":"text/html;charset=utf8"
})
if(method == "get"){
if(pathname == "/" || pathname == "/index"){
res.end("首页")
}else if(pathname == "/list"){
res.end("列表页")
}else{
res.end("not found")
}
}else if(method == "post"){
}
})
app.listen(3000)
console.log("启动成功");
静态 动态资源
const http = require('http');
const url = require('url')
const path = require("path")
const fs = require('fs');
const mime = require('mime')
const app = http.createServer();
app.on("request",(req,res)=>{
let pathname = url.parse(req.url).pathname;
//什么都不输入也是默认为index.html
pathname = pathname == "/" ? "/index.html" : pathname;
//将请求路径转化为硬盘路径
let realpath = path.join(__dirname,"public",pathname)
//mime动态改变请求
let type = mime.getType(pathname);
fs.readFile(realpath,(error,result)=>{
if(error != null){
res.writeHead(404,{
"content-type":"text/html;charset=utf-8"
})
res.end("不存在的路径");
return;
}
//这里输出的是html主文件 而主文件里又有不同的外链接
//可能是css,jpg,video 所以不能写死
//所以需要一个库npm i mime
//新版浏览器不需要,旧版可能会出问题
res.writeHead(200,{
"content-type":type
})
res.end(result);
})
})
app.listen(3000)
console.log("启动成功");
异步 同步的概念
有两种方式
接受返回值
const publicPath = path.join(_dirname,"public");
const urlObj = url.parse(req.url);
使用函数
fs.readFile(publicPath,(error,result)=>{
console.log(result);
})
同步api可以从返回值拿到api的执行结果,异步的不可以
fuction sum(n1,n2){
return n1+n2;
}
var result = sum(10,20); //这里可以通过返回值拿到相加结果30
异步
function sum2(n1,n2) {
setTimeout(() => {
return "helloword";
}, 2000);
}
var b = sum2()
console.log(b);
回调函数
function sum2(cb) { //不能通过return只能通过回调函数
setTimeout(() => {
cb({
msg: "hello"
})
}, 2000);
}
sum2((n) => { console.log(n) })
node里的读取文件之类的用的就是回调函数
function sum2(cb) {
setTimeout(() => {
cb({
msg: "hello"
})
}, 2000);
}
sum2((n) => {
console.log("我是n", n)
//修改对象
n.msg = "修改完毕"
console.log("改了",n);
})
如
fs.readFile("./demo.txt" , (err.result) => {})
执行顺序
先执行同步,在执行异步执行
同步代码执行区域 异步代码执行区域
回调函数队列
先同步 遇到异步就放到异步执行区
等同步执行完毕在执行异步代码
异步执行完一条就给回调 回调到同步区
回调地狱
后面的异步需要前面异步的结果
回调嵌套在嵌套 回调地狱
就是一层回调在嵌套一层回调 不易维护
fs.readFile("./1.txt", "utf-8", (err, result1) => {
console.log(result1);
fs.readFile("./2.txt", "utf-8", (err, result2) => {
console.log(result2);
fs.readFile("./3.txt", "utf-8", (err, result3) => {
console.log(result3);
})
})
})
es6可以用promise来解决回调地狱的问题
let p1 = new Promise((resolve, reject) => {
fs.readFile("./1.txt", "utf-8", (err, result) => {
if (err != null) {
reject(err); //如果失败就调用这个传值下面能拿到
} else {
resolve(result); //如果成功就用resolve把异步结果传出去
}
})
})
//then这里就相当于是上面的resolve()函数
p1
.then((result) => {
console.log(result);
})
.catch((err) => {
console.log(err);
})
promise进阶
function p1() {
return new Promise((resolve, reject) => {
fs.readFile("./1.txt", "utf-8", (err, result) => {
resolve(result);
})
})
}
上面返回那个promise对象下面才能then
p1().then((result)=>{
console.log(result);
})
解决回调地狱
function p1() {
return new Promise((resolve, reject) => {
fs.readFile("./1.txt", "utf-8", (err, result) => {
resolve(result);
})
})
}
function p2() {
let p = new Promise((resolve, reject) => {
fs.readFile("./2.txt", "utf-8", (err, result) => {
resolve(result);
})
})
return p;
}
function p3() {
return new Promise((resolve, reject) => {
fs.readFile("./3.txt", "utf-8", (err, result) => {
resolve(result);
})
})
}
链式调用
p1()
.then((r1) => {
console.log(r1);//第一个文件的结果
return p2();
})
.then((r2)=>{
console.log(r2);
return p3();
})
.then((r3)=>{
console.log(r3);
})
async await es7异步函数 基于promise封装
//在普通函数定义的前面加上async关键字 普通函数就变成了异步函数
//在异步函数默认的返回值是promise对象
async function fn(){
}
console.log(fn());
返回 Promise { undefined }
async function fn(){
return 123
}
console.log(fn());
返回 Promise { 123 }
既然返回值是promise对象那么
async function fn(){
return 123
}
fn().then((data)=>{
console.log(data);
})
捕获错误
async function fn(){
throw "发生错误"; 有throw时 return则不起作用
return 123;
}
fn().catch(err=>{
console.log(err);
})
await关键字 只能出现在异步函数当中
后面跟 promise对象 它可以暂停异步函数的执行
等待promise对象返回结果后 在向下执行
后面只能跟promise对象 后面只能跟promise对象 后面只能跟promise对象
暂停异步函数向下执行 直到promise返回结果
async function p1(){
return "p1"
}
async function p2(){
return "p2"
}
async function p3(){
return "p3"
}
async function run(){
let r1 = await p1() //可以通过返回值 不需要then了
let r2 = await p2() //异步代码写成了同步形式
let r3 = await p3() //实际就是用上面的return代替了以前的resolve,throw代替错误
console.log(r1);
console.log(r2);
console.log(r3);
}
run()
node异步函数的实际使用
需要借助模块util
const fs = require('fs');
const promisify = require("util").promisify
const readFile = promisify(fs.readFile); //用调用的api方法改造返回promise
async function run(){
let r1 = await readFile("./1.txt","utf-8",)
let r2 = await readFile("./2.txt","utf-8",)
let r3 = await readFile("./3.txt","utf-8",)
console.log(r1);
console.log(r2);
console.log(r3);
}
run()
捕获错误
const fs = require('fs');
const promisify = require("util").promisify
const readFile = promisify(fs.readFile); //用调用的api方法改造返回promise
async function run(){
let r1 = await readFile("./111.txt","utf-8",).catch(err=>{
console.log(err);
})
let r2 = await readFile("./2.txt","utf-8",)
let r3 = await readFile("./3.txt","utf-8",)
console.log(r1);
console.log(r2);
console.log(r3);
}
run()
node全局对象global
浏览器中全局是window,node中全局对象是global
node全局对象下有以下方法,可以在任何地方使用,global可以省略
console.log()
setTimeout()
clearTimeout()
setInterval() //设置间歇定时器
clearInterval() //清除简写定时器
另一个node笔记
初识
cd ../
node ./test.js tab补全 clear清楚历史记录
模块化开发
文件与文件依赖关系不明确
文件与文件命名冲突
就像装机一样 主机显示器键盘鼠标 一个模块坏了不会影响另一个模块
模块化开发规范
一个js文件就是一个模块
模块内部定义的变量和函数默认情况下在外部无法得到
模块内部的函数变量可以导出 exports 使用require导入
A模块(a.js) B模块(b.js)
加法函数
减法函数 A模块 = require(A模块)
A模块.加法()
exports.加法 = 加法
实例
//a.js
//定义变量
var version = 1.0;
//定义方法
var sayHi = function(name){return `您好${name}`};
//导出
exports.version = version;
exports.sayHi = sayHi;
模快成员导出 exports require
test1
//定义一个函数
var add = function (n1, n2) { return n1 + n2 }
exports.add = add; //exports对象的add属性等于test1里面的add函数
test2
const a = require("./test1.js"); // 拿a来接 require("./test1"); .js可以省略
console.log(a);
console.log(a.add(10,20));
结果
PS C:\Node.js> node .\test2.js
{ add: [Function: add] }
30
模块成员导出 module.exports
//test1
var greeting = function (name) { return `hello ${name}!`};
module.exports.greeting = greeting;
//test2
const a = require("./test1")
console.log(a);
console.log(a.greeting("张三"));
PS C:\Node.js> node .\test2.js
{ greeting: [Function: greeting] }
PS C:\Node.js> node .\test2.js
hello 张三!
两者导出区别 如果重新指向 以module.exports为准
两者默认指向用一个对象(同一块内存空间)
module.exports.greeting = greeting;
exports.greeting = greeting; 两者 指向相同
但是 如果重新指向 以module.exports为准
module.exports = {
name:"张"
}
实例
var greeting = function (name) { return `hello ${name}!`};
var x = 100;
exports.x = x;
module.exports.greeting = greeting;
const a = require("./test1")
console.log(a);
PS C:\Node.js> node .\test2.js
{ x: 100, greeting: [Function: greeting] }
重新指向
var greeting = function (name) { return `hello ${name}!`};
var x = 100;
exports.x = x;
module.exports.greeting = greeting;
module.exports = {
name:"张三"
}
const a = require("./test1")
console.log(a);
PS C:\Node.js> node .\test2.js
{ name: '张三' }
系统模块 Node运行环境提供的api 因为模块化的方式开发所以叫
文件模块 fs
f file文件 s system系统
//引入
const fs = require("fs");
文件模块 fs
f file文件 s system系统
读取操作
//引入
const fs = require("fs");
//读取文件内容
fs.readFile("文件路径/名称",["文件编码"],function(err,doc文件内容){}) //回调函数
fs.readFile("../css/base.css","utf-8",function(err,doc){
//如果文件读取出错 err是一个对象 包含错误信息
//如果文件读取正确 err是null
//doc是文件内容 文件读取的结果
if(err == null){
console.log(doc);
}
})
const fs = require("fs");
fs.readFile("./test2.js", "utf8", function (err, doc) {
console.log(err);
console.log(doc);
})
写入操作 错误日志
//如果文件读取正确 err是null
fs.writeFile("文件名称/文件路径","数据",function(err){})
const fs = require("fs");
var error = "正在写入数据";
fs.writeFile("./testtest.txt", error, function (err) {
if(err != null){
console.log("写入失败");
console.log(err);
return;
}
console.log("写入成功");
})
路径操作 path Linux和windows路径写法不一样
win为/
linux为/
path.join("路径","路径",.......)
//实例
const path = require("path");
//路径为cast\a\b\c.css
var finialPath = path.join("cast","a","b","c.css")
console.log(finialPath);
//输出为cast\a\b\c.css
第三方模块 也名为 包
别人写好的具有特定功能的 因为通常是多个文件所以 也名为包
通常具有两种存在形式
- js文件的形式存在,提供实现项目具体功能的API接口
- 命令行工具形式存在,辅助项目开发
如何获取第三方模块 https://npmjs.com
npm(node package manager) node的第三方模块管理工具
下载node时已经被继承在里面了
下载 npm.install 模块名称 //默认保存位置时当前的工作位置
如下载 formidable
npm install formidable
删除模块 npm unintsall 模块名称
本地安装 全局安装 上面为本地安装
一般命令行工具全局安装 第三方本地安装
nodemon命令行工具 nodemon每次保存就会自动执行
辅助项目开发
在node.js中每次写完都要调 命令行控制台执行 非常麻烦
nodemon每次保存就会自动执行
// 步骤
npm install nodemon -g // -g代表全局安装
命令行里用nodemon 替代node来执行
nodemon test1.js
结束用Ctrl + c
nrm下载地址切换工具
npm registry manager
国内阿里巴巴 等 做了国内服务器
npm install nodemon -g 安装
nrm ls 列出可用下载地址列表
nrm use 下载地址名称 切换下载地址
* npm -------- https://registry.npmjs.org/
yarn ------- https://registry.yarnpkg.com/
cnpm ------- http://r.cnpmjs.org/
taobao ----- https://registry.npm.taobao.org/
nj --------- https://registry.nodejitsu.com/
npmMirror -- https://skimdb.npmjs.com/registry/
edunpm ----- http://registry.enpmjs.org/
nrm use taobao
第三方模块 gulp 基于node平台开发的前端构建工具
基本
将机械化的操作编写成任务,想要执行机械化操作时,执行一个命令行命令就能自动执行了
能做什么
- html css js 文件压缩合并
- 语法转换(es6,less)
- 公共文件抽离(将头部抽取出来 要修头部直接改
- 修改浏览器自动刷新
使用步骤
- npm install gulp 下载库文件
- 在项目根目录创建gulpfile.js文件 文件名不能改
- 重构项目文件夹结构 src目录放置源代码文件 dist放置构建后文件
- 在gulpfile.js文件中编写任务
- 在命令行中执行gulp任务下载命令 npm install gulp-cli -g
- 下好gulp命令行 执行命令不在是node而是gulp (在文件根目录下)
gulp中提供的一些api方法
gulp.src(); 获取任务要处理的文件
gulp.dest(); 输出文件
gulp.task(); 建立gulp任务
gulp.watch(); 监控文件的变化
实例
//引入
const gulp = require("gulp");
//使用gulp.task方法建立任务 参数 任务名字 函数
gulp.task("first",function(){
console.log("任务执行了");
//获取要处理的文件 //将处理后的文件输出到dist目录
gulp.src("./src/css/index.css") .pipe(gulp.dest("./dist/css"));
});
gulp插件
gulp-htmlmin html压缩
gulp-csso css压缩
gulp-babel JavaScript语法转化
gulp-less less语法转化
gulp-uglify 压缩混淆JavaScript
gulp-file-include 公共文件包含 抽取公共代码
browsereync 浏览器实时同步
插件的使用
- 下载
- 在gulpfile.js引入
- 调用
html压缩任务
//html文件中代码的压缩操作
//抽取html文件中的公共代码
//下载命令
npm install gulp-htmlmin
npm install gulp-file-include
const htmlmin = require("gulp-htmlmin");
const fileinclude = require('gulp-file-include');
//html压缩任务//html公共代码抽离
gulp.task("htmlmin", function () {
//所有html文件
gulp.src("./src/*.html")
//html公共代码抽离 同时在src下创建common文件夹放公共代码片段 同时在html里剪切到新文件 在原来文件位置@@include('./common/header.html')
.pipe(fileinclude())
//压缩代码 要压缩空格吗? 是
.pipe(htmlmin({ collapseWhitespace: true }))
//输出文件
.pipe(gulp.dest("./dist"));
});
控制台gulp htmlmin
css压缩 less转化
npm install gulp-csso
npm install gulp-less
const csso = require("gulp-csso");
const less = require("gulp-less");
//css任务代码压缩 less语法转换
gulp.task("cssmin", function () {
gulp.src(["./src/css/*.less","./src/css/*.css"]) //这里多选得加[]
.pipe(less()) //这里先转化
.pipe(csso()) //在压缩
.pipe(gulp.dest("./dist/css")); //在输出
})
gulp cssmin
js语法转换 代码压缩
npm install --save-dev gulp-babel @babel/core @babel/preset-env
npm install gulp-uglify
const uglify = require("gulp-uglify");
const babel = require("gulp-babel");
拷贝文件夹
// 复制文件夹
gulp.task("copy", function () {
gulp.src("./src/img/*")
.pipe(gulp.dest("./dist/img"));
gulp.src("./src/favicon.ico")
.pipe(gulp.dest("./dist"));
})
执行一个任务 都执行 构建任务
gulp.task("default",["htmlmin","cssmin","jsmin","copy"]);
控制台执行 gulp default 当任务名为default 则可以直接敲 gulp