Node.js是啥?
node.js是构建在Chrome v8 引擎上的一个javascript 运行环境
node和Chrome一样都是基于事件驱动的异步架构!Chrome是基于事件的交互,而node是基于事件的I/O;
node没有HTML、Webkit和显卡驱动等UI技术支持;
文件引入
如果当前文件夹下有index.js和2.js
2.js 里包含变量a(let a=1)
//2.js
let a=1
global.b=ouyang; //挂载在global全局下,node的全局是global不是window
//index.js
const obj=require("./2.js"); //require请求的就是module.exports的内容
console.log(obj.a); //输出2.js里的a不会成功
console.log(global.b); //ouyang 这样才会成功
node在执行时会把代码重新编译,编译时会把代码打包成字符串放入一个函数里进行编译,所以直接在全局var 或者let声明的变量并不能通过全局直接调用!
模块
//02.js
module.exports=function(){
console.log("666")
}; //被覆盖
module.exports=123123123; //为模块赋值
// module.exports.num=123; //可以为模块定义属性
//index.js
const obj=require("./2.js"); //如果不加./ 则在核心模块或第三方依赖模块里找,就不再当前文件夹下找了
console.log(obj); //123123123
重新定向
//2.js
exports=module.exports
exprots.fn=function(){
}; //对exports重新定向,并添加新的属性fn,方便index.js的require访问;
node把所有抽象成了事件,node执行时,同步异步差异如下:
// 同步
process.nextTick(()=>{
console.log("1") //2
})
process.nextTick(()=>{
console.log("2") //3
})
//异步
setImmediate(()=>{
console.log("3") //6
process.nextTick(()=>{
console.log("4")//8
}
})
setImmediate(()=>{
console.log("5") //7
})
setTimeout(function(){
console.log("8") //5
},0)
//同步
process.nextTick(()=>{
console.log("7") //4
})
console.log("6") //1
node 输出结果 6 1 2 7 8 3 5 4
事件队列,自动排队
macro-task:script(全部代码) (setInterval setTimeout定时器,同优先级谁先注册谁高) setImmediate I/O
micro-task:process.nextTick Promise=>then
同步的是整体代码,而异步之所以异步是将参数里的回调函数在将来执行
node执行初期执行一个无线循环
while(true){
1.scipt(全部代码),产生同步异步;
2.执行完script后 将micro-task 队列里的事件全部执行;
3.再次执行macro-task 队列里的第二层script,产生第二层的micro-task的
4.紧接着执行micro-task里新产生的事件队列
一直到最里层的macro-task代码产生的micro-task队列执行完毕…
}
Promise.resolve("1").then(res=>console.log(res))
//Promise是同步的,then是异步的(将来执行的)
process.nextTick((=>{
console.log("2")
})
setTimeout((=>{
console.log("3")
},0);
console.log("4")
第一次循环:
macro-task:script(第一层代码,检查到有log 4 ) setTimeout=>3
micro-task:process.nextTick=>2 Promise=>then 1
第二次循环:
macro-task:{script(第一层代码,检查到有log 4 )}->第一次已执行 setTimeout=>3->第二次正在执行
micro-task:{process.nextTick=>2 Promise=>then 1}->第一次已执行
mode输出结果 4 2 1 3
总结优先级,可以简单看为:
nextTick > Promise.then > setTimeout > setImmediate
下载包
npm.nodejs.com–>sort by keywords search
运行使用nodejs
实现在控制台进入当前文件夹,node + 文件名 回车执行
- 初始化项目信息
//初始化项目环境
npm init
//确认初始化对象,输入名称
package name: nodetest
//确认版本等信息,默认回车
//直到出现Is this OK? 回车
//初始化后生成一个package.json 文件,就是上面的配置信息。
npm init -y //一路回车默认配置信息
- 安装模块
npm install 模块名 参数 //npm install webpack -g 全局安装webpack包,同时安装多个包用空格隔开
//安装时会把相关依赖的包同时安装在当前控制台所在的目录路径
//如安装koa包,--save是安装在当前文件夹,-g是本地,安装在dependencies里代表上线时会使用的包,而koa-router --save-dev 代表生产环境使用的包,将在配置文件package.json 的测试用包,-D代表 --save-dev
npm install koa --save
//引用时:
const Koa = require("Koa");
const app = new Koa();
app.use(async(ctx)==>{
ctx.body="这是后台返回的数据"
})
app.listen(3000);
//指定版本
npm install koa@7.0.1 //不指定默认最高版本
- 添加上传使用用户
npm adduser
Username: 你的名字
Password: (不可见)
...
//登录
npm login
Username:
Password:
Email:
//上传
npm publish
//上传当前初始化的node环境里的文件,同时会对比以前的文件
- 如果国外服务器卡顿,使用淘宝镜像
node原生模块
- 事件模块 events
const events=require("events"); //使用下面的对象时直接加“.EventEmitter”使用 events获得的是构造函数,用new创建实例
如:
const eventEmitter=require("events").EventEmitter;
const myEmitter=new EventEmitter();
//这里有一个异步
setTimeout(()=>{
//异步的结果出来
},2000);
myEmitter.on("someEvents",()=>{
console.log("这个某个异步的回调执行函数")
}
或者:
const eventEmitter=require("events").EventEmitter;
const myEmitter=new EventEmitter();
const fn=()=>{
console.log("这个某个异步的回调执行函数")
}
//这里有一个异步
setTimeout(()=>{
//异步的结果出来
myEmitter.emit("fengyu")
},2000);
myEmitter.on("fengyu",fn}; //第一个参数是绑定的监听名号,第二个是回调函数,异步结果执行的函数
- 自定义模块的原型
const eventEmitter=require("events").EventEmitter;
const myEmitter=new EventEmitter();
function Fn=(name)=>{
this.name = name;
}
Fn.prototype.__proto__ = EventEmitter.prototype; //将模块的原型赋值到Fn的默认原型
const obj=new Fn("大坏蛋");
obj.on("fy",function(){
console.log(this.name);
})
setTimeout(()=>{
//异步的结果出来
myEmitter.emit("fy")
},2000);
//node+文件名 在控制台执行
const eventEmitter=require("events").EventEmitter;
const myEmitter=new EventEmitter();
myEmitter.on("newlistenner",function(){
console.log("绑定了一个新的方法");
})
myEmitter.on("fy1",()=>{}); //触发log1次
myEmitter.on("fy2",()=>{}); //触发log第二次
//myEmitter.off可以去除
//myEmitter.getMaxListenners()可以设置myEmitter实例的on函数可以绑定的最大事件绑定次数,可以用setMaxListenner(数值)更改,默认10
//myEmitter.listenners()可以查看on对第一个参数名称相同的事件绑定了多少响应回调函数
- path模块
const path=require('path')
console.log(path.join("a","b"))//用于拼接路径 a/b
console.log(__dirname); //返回文件夹路径
console.log(__filename); //返回文件路径,包含文件名
console.log(path.resolve(__dirname,"test"); //返回一个绝对路径
console.log(path.parse(__filename)); //序列化传入的参数如下格式
/*
{
root:'/',
dir:'',
base:'',
name:''
}
*/
URL模块
- 导入URL模块
const {URL} = require("url"); //建议加上.URL,不适用node自己实现的方法
const myUrl=new URL("https://www.baidu.com");
console.log(myUrl); //解析出整个url的各种值并转化为json数据
//search:'' 为查询部分
//URLsearchParams:'' 这是一个类似的map对象
//如果用parse序列化
const myUrl2=url.parse("https://www.baidu.com");
查询字符串querystring
const qs =require('querystring');
const queryObj=qs.parse(myUrl.search.slice(1))
console.log(queryObj); // 通过. 使用里面的数据
断言 assert
用于判断得到的值是否为期望值
const assert = require('assert');
//assert(布尔值,报错信息)
assert(true,"如果第一个参数的布尔值不为true,这个字符串就为报错信息!")
//或:assert(表达式,预期,报错信息)
加密模块
const crypto = require('crypto');
const KEY="fengyu";
const obj=crypto.createHash('md5');
obj.update(KEY);
const password=obj.digest('hex'); //输出刚才的结果,1次 参数可以选择进制位数等
文件操作 js
const js = require('fs')
fs.readFile('路径',(err,data)=>{
if(err) threw err;
console.log(data);
}); //有Sync 同步 没有回调, 没有Sync 异步有回调 ,错误对象err永远是第一个参数位;
//如果读取错误,err是个json对象,不为null,包含路径,结果,权限等键与值
//输出的data一般是个buffer数据,如果添加第二个参数(进制编码),可以将data转换为其他文字编码,如UTF-8
//异步读取
const js = require('fs')
const fn=async()=>{
<!--await fs.readFile("./1.txt","utf8",fucntion(err,data){
if(err)return;
return data;
} //取不到-->
const data =await new Promise((resolve,reject)=>{
fs.readFile("./1.txt","utf8",(err,data)=>{
if(err) return reject(err)
resolve(data)
}
}
console.log(data); //取不到
}
//同步读取
const js = require('fs');
const data=fs.readFileSync("./2.txt","utf8");//读取错误立马报错
//写
const js = require('fs');
const data="fengyu";
fs.writeFile("./2.txt",data,'utf8',err=>{
if(err) throw err;
console.log("写入成功");
}) //utf8 编码参数可选
//写
const js = require('fs');
const data="fengyu";
创建服务器实例
const http=require('http')
const fs=require('fs')
const server=http.createServer((req,res)=>{
res.writeHead(200,{
"Content-Type:"text/plain;charset=utf-8"
"}); //响应头,text/plain 是纯文本,charset设置文字编码
res.write("向客户端返回数据"); //数据响应,返回值
res.end()l//结束响应
}); //req requeset, res response
//修改后打断^C,重新执行, 或者安装 npm全局安装nodemon
server.listen(3000); //建议监听1024以上
//返回页面
if(req.method==="GET"){
res.writeHead(200,{"Content-Type":"text/html;charset=utf-8"})
switch(req.url){
case "/":
res.write(fs.redFileSync("index.html","utf8"));
<!--
fs.readFile("index.html","utf8",(err,data)=>{
res.write(data)
res.end();//由于是异步的,fs的readFirefile执行在后面的end后,需要把end提到这里面主动提前执行end
}
-->
<!--
如果使用管道流
fs.createReadStream("index.html").pipe(res);
-->
}
}
const http=require('http')
const server=http.createServer((req,res)=>{
const obj={
a:1,
b:2
}
res.write(JSON.stringfy(obj)
})
server.listen(3000,()=>{
console.log("服务器监听在localhost:3000")
})
框架 Koa
cosnt Koa= require('koa')
const app =new Koa
//中间件 理论上可以注册任意多个 洋葱模型
app.use(async(ctx,next)=>{
await next();//提交到下一层
});//ctx context 上下文环境
- 路由管理
router.get("/",async (ctx,next)=>{
//只有同时满足在根路径下get请求方式才能进入此中间件,"/"代表根路径,可以改成/home /home/index等等
console.log(1*)
await next()
console.log(1=)
},async(ctx,next)=>{ //第二个中间件
console.log(2*)
await next()
console.log(2=)
})
// 1* 2* 2= 1=
app.use(router.routes()),
use(router.alloweMethods());//挂载中间件在app上执行
RESTfull规则
npm安装koa-static 管理静态资源
Pug模板引擎
需要 koa pug koa-views(视图管理)
const Koa=require('koa')
const views=require('koa-views')
const {join}=require('path') // 使用join链接
//pug不需要实例,可以自动识别
const app=new Koa
app.use(views(join(__dirname,"views"),{
extension:'pug' //模板pug,views是文件夹名,路径下有个views文件夹
})) //一定要在其他中间件之前注册模板信息
app.use(async(ctx)=>{
ctx.render("index.pug") //渲染模板
})
app.listen(3000)
MongoDB
- 安装
一路默认即可,路径最好在根目录,确认安装环境,如果没有要添加到系统的环境变量里
- 启动服务:
mongod --dbpath Desktop/demo/db
启动服务并初始化目录,完成时会提示连接的监听端口,默认是27017(关闭窗口会断开连接) - 客户端连接:
mongo
- 查看数据库集合:
show dbs
- 创建数据库:
use DATABASE_NAME
- 查看正在使用的集合:
db
概念: 库database,集合collection
//use 就创建了数据库,并进入当前数据库
> use test //dropDatabase 删除当前数据库
switched to db test
//createCollection创建集合
> db.createCollection("runoob")
{ "ok" : 1 }
> show collections
runoob
//添加数据
> db.runoob.insert({"name" : "fengyu","length":"10"})
//db.runoob.drop()删除集合
//find不加参数查找当前目标集合的所有数据,可以传参,内容为数据里的信息
> db.runoob.find()//find({"name":"fengyu"})
- 其他主机连接服务器数据库
const mongoose=require('mongoose')
const db=mongoose.createConnection("mongodb://localhost:27017/fengyu",{userNewRulParser:true})
//用es6原生的Promise取代MongoDB自实现的Promise
mongoose.Promise=global.Promise
//操作数据库之前,使用Schema设置每个字段的数据类型
db.on("error",console.log.bind(console."数据库连接失败"))
db.on("open",(=>{
console.log("数据库连接成功")
})
//连接成功-->操作数据库-->设置Schema
const Schema=mongoose.Schema
const JavaScriptSchema=new Schema({
name:String,
age:Number,
sex:{
type:String,
default:"男"
}
})
const JavaScript=db.model("javascript"/*集合名,默认加s*/,JavaScriptSchema/*定义的数据结构*/) //模式化数据,返回一个对象
const data={
name:"大帅比",
age:27
}
const data2={
name:"小清新",
age:18,
sex:"女"
}
//插入上面准备的数据
const d1=new JavaScript(data) //实例,结构化数据
d1.save().then(err,,res)=>{ //保存,即数据库的创建插入等操作
console.log(err)
})