非阻塞处理:继续执行后面的。(必须提供回调函数)
function updb2(done){ setTimeOut(()=>{ done() },3000)}updb2(function(){ console.log('数据库更新成功!')})console.log('其他语句')
四 搭建http服务器- http模块(nodejs内置模块)
- 参考文档:http://nodejs.cn/api/http.html
const http=require('http');const hostname='127.0.0.1';const port=3000;const server=http.createServer((req,res)=>{ res.statusCode=200;//设置状态码 res.setHeader('Content-Type','text/plain')//设置响应头 res.end('Hello World')})server.listen(port,hostname,()=>{ console.log(`Server running at http://${hostname}:${port}/`);})
一般情况下,每次更代码都需重新启动服务器,否则页面将没有变化。supervisor工具可以在不用重复启动服务器的情况下就能看到页面变化:
npm install -g supervisor//全局安装supervisor app.js//使用supervisor替代node命令来运行程序
五 引入自定义模块
默认情况下js文件是私有的。要让外部访问,需通过exports或module.exports暴露:
- require:引用外部文件
- exports、module.exports:公开文件
例子:hostname和port属于公共部分,可以抽出来作为模块
config.js
const cOnfig={ hostname:'127.0.0.1', port:3000}exports.cOnfig=config
server.js
const http=require('http');const cOnfig=require('./config').config //引用模块const server=http.createServer((req,res)=>{ res.statusCode=200; res.setHeader('Content-Type','text/plain') res.end('Hello World')})server.listen(config.port,config.hostname,()=>{ console.log(`Server running at http://${config.hostname}:${config.port}/`);})
另一种写法:
config.js
const cOnfig={ hostname:'127.0.0.1', port:3000}module.exports=config
server.js
const cOnfig=require('./config')
六 路由
const http=require('http');const hostname='127.0.0.1';const port=3000;const server=http.createServer((req,res)=>{ res.statusCode=200; res.setHeader('Content-Type','text/plain') switch(req.url){ case '/': res.end('Hello World'); break; case '/about': res.end('This is about page') break; case '/home': res.end('Welcome to myhomepage') break; default: res.end('404 NOT FOUND!') }})server.listen(port,hostname,()=>{ console.log(`Server running at http://${hostname}:${port}/`);})
七 搭建静态服务器- fs模块(node内置模块)——指路-官方文档
- path模块(node内置模块)——指路-官方文档
- Content-Type:表示具体请求中的媒体类型信息
7.1 读取html
./index.html
Hello world!
./server.js
const http=require('http');const fs=require('fs')//__dirname:当前文件所在目录const server=http.createServer((req,res)=>{ fs.readFile(__dirname+'/index.html','utf-8',(err,data)=>{ if(err){ res.setHeader('Content-Type','text/plain');//纯文本 res.statusCode=404; res.end('404 Not Founded!') }else{ res.setHeader('Content-Type','text/html');//html res.statusCode=200; res.end(data) } })})const hostname='127.0.0.1';const port=3000;server.listen(port,hostname,()=>{ console.log(`Server running at http://${hostname}:${port}/`);})
7.2 读取其他
由于不同文件的Content-Type不一样,所以这里封装一个根据后缀名获取文件Content-Type的方法:
./modules.js
const fs=require('fs')exports.getMimeType=function (extname){ let data=fs.readFileSync('./mime.json') let mimeObj=JSON.parse(data.toString())//转为对象 return mimeObj[extname]};//mime.json可在网上找:格式{".html": "text/html"}
./server.js
const http=require('http');const fs=require('fs')const path=require('path');const common=require('./modules');const server=http.createServer((req,res)=>{ let pathname=req.url pathname=pathname=='/'?'/index.html':pathnamelet extname=path.extname(pathname)//获取文件后缀名 fs.readFile('./static'+pathname,(err,data)=>{ if(err){ res.setHeader('Content-Type','text/plain'); res.statusCode=404; res.end('404 Not Founded!') }else{ let mime=common.getMimeType(extname) res.setHeader('Content-Type', mime+";charset='utf-8'"); res.statusCode=200; res.end(data) } })})const hostname='127.0.0.1';const port=3000;server.listen(port,hostname,()=>{ console.log(`Server running at http://${hostname}:${port}/`);})
7.3 封装静态服务器
./module/route.js
const fs=require('fs')const path=require('path');const url=require('url');function getMimeType(extname){ let data=fs.readFileSync('./mime.json') let mimeObj=JSON.parse(data.toString())//转为对象 return mimeObj[extname]};exports.static=function(req,res,staticPath){ let pathname=url.parse(req.url,true).pathname pathname=pathname=='/'?'/index.html':pathname let extname=path.extname(pathname) fs.readFile('./'+staticPath+pathname,(err,data)=>{ if(err){ res.setHeader('Content-Type','text/plain'); res.statusCode=404; res.end('404 Not Founded!') }else{ let mime=getMimeType(extname) res.setHeader('Content-Type', mime+";charset='utf-8'"); res.statusCode=200; res.end(data) } })}
./server.js
const http = require('http');const route= require('./module/route');http.createServer(function (req, res) { route.static(req, res,'static')}).listen(3000);
八 使用第三方包ejs- ejs(effective Javascript template)(第三方模块)——指路-官方文档
- querystring(node内置模块)——查询字符串,指路-官方文档
- npm:Nodejs附带的第三方软件包管理器。是世界上最大的开放源代码的生态系统,可通过它下载各种各样的包,为Nodejs提供更多的功能支持——指路-npm与依赖包
- fs
8.1 基本使用
安装
npm install ejs
./helo.ejs
./server.js
const http=require('http');const fs=require('fs')const ejs=require('ejs')var template=fs.readFileSync(__dirname+'/helo.ejs','utf-8'); const server=http.createServer((req,res)=>{ //模板渲染-传值 var data=ejs.render(template,{ title:'helo ejs', content:'big helo ejs.' }) res.setHeader('Content-Type','text/html'); res.statusCode=200; res.end(data)})const hostname='127.0.0.1';const port=3000;server.listen(port,hostname,()=>{ console.log(`Server running at http://${hostname}:${port}/`);})
8.2 get/post
./list.ejs
- <% for(let i=0 ; i
./server.js
const http=require('http');const fs=require('fs')const ejs=require('ejs')const qs=require('querystring') //+ 处理用户提交的表单数据var template=fs.readFileSync(__dirname+'/list.ejs','utf-8'); var posts=[] //+ 用户输入的内容const server=http.createServer((req,res)=>{ if(req.method==='POST'){ req.data=""; req.on("data",function(postDataChunk){ req.data+=postDataChunk }) req.on("end",function(){ //表单处理 let query=qs.parse(req.data)//将数据进行内部解析,生成查询变量 posts.push(query.content)//content就是取到表单name为content的内容 showForm(posts,res) }) }else{ showForm(posts,res) }})//渲染页面function showForm(posts,res){ let data=ejs.render(template,{ title:'列表', posts }) res.setHeader('Content-Type','text/html'); res.statusCode=200; res.end(data)}const hostname='127.0.0.1';const port=3000;server.listen(port,hostname,()=>{ console.log(`Server running at http://${hostname}:${port}/`);})
九 使用MongoDB- MongoDB入门——指路-使用MongoDB
- MongoDB的node驱动——指路-官方网站
- assert(内置模块)——指路-官方文档
9.1 连接MongoDB
驱动安装
npm install mongodb --save
./connect.js
//mongodb客户端const MOngoClient=require('mongodb').MongoClient// 判断某两值是否相等的库const test=require('assert')// mongodb的连接地址const url='mongodb://127.0.0.1:27017'// 数据库名称-指定数据库名称const dbName='admin'// 连接使用客户端MongoClient.connect(url, function(err, client) { test.equal(null, err);//判断错误对象是否为空,为空说明成功 const adminDb = client.db(dbName)// 打开数据库进行操作 console.log('链接数据库成功') client.close();});
9.2 插入数据
./insert.js
const MOngoClient=require('mongodb').MongoClientconst test=require('assert')const url='mongodb://127.0.0.1:27017'const dbName='mydata'//这里的mydata数据库是提前创建好的,其下创建了posts集合。MongoClient.connect(url, function(err, client) { test.equal(null, err); const db = client.db(dbName) console.log('链接数据库成功') db.collection("posts").insertMany( [ {title:"今天不是很热",tag:"life"}, {title:"外卖还没到,非常饿!",tag:"life"}, ], (err,result)=>{ test.equal(null,err) client.close(); } )});
9.3 查询数据
./find.js
const MOngoClient=require('mongodb').MongoClientconst test=require('assert')const url='mongodb://127.0.0.1:27017'const dbName='mydata'MongoClient.connect(url, function(err, client) { test.equal(null, err); const adminDb = client.db(dbName) console.log('链接数据库成功') adminDb.collection("posts").find({tag:"study"}).toArray((err,docs)=>{ test.equal(null, err); console.log(docs) client.close() })});
十 处理异步
引言-异步/非阻塞的处理方式
10.1 回调地狱
Node.js是非阻塞编程,那么在编码过程中会遇到很多的回调函数(Callback),如果多个处理的回调函数嵌套在一起的话,就会形成回调地狱,虽然对于程序的结果没有任何影响,但对于程序代码的可读性来说就是个地狱。
function dbupd(sql, done) { setTimeout(() => done(sql + " upd ok."), 800);}dbupd("1.sql1", result => { console.log(result); dbupd("2.sql2", result => { console.log(result); dbupd("3.sql3", result => { console.log(result); }); });});
10.2 Promise解决
// Promise函数嵌套解决方法function dbupAsync(sql) { const p = new Promise((resolve, reject) => { setTimeout(() => { console.log(sql + " upd ok."); resolve(sql + ".ok"); }, 800) }); return p;}
方法一:
dbupAsync("2.sql1") .then(() => dbupAsync("2.sql2")) .then(() => dbupAsync("3.sql3"));
方法二:async/await 更简洁
async function upAllDB() { const result1 = await dbupAsync("3.sql1"); const result2 = await dbupAsync("3.sql2"); const result3 = await dbupAsync("3.sql3"); console.log(result1, result2, result3);}upAllDB();
十一 封装express路由
./moudle/route
const fs=require('fs')const path=require('path');const url=require('url');//获取文件类型function getMimeType(extname){ let data=fs.readFileSync('./mime.json') let mimeObj=JSON.parse(data.toString())//转为对象 return mimeObj[extname]};//扩展resfunction changeRes(res){ res.send=(data)=>{ res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' }); res.end(data); }}//静态web服务的方法function initStatic(req, res, staticPath) { //1、获取地址 let pathname = url.parse(req.url).pathname; pathname = pathname == '/' ? '/index.html' : pathname; let extname = path.extname(pathname); //2、通过fs模块读取文件 try { let data = fs.readFileSync('./' + staticPath + pathname); if (data) { let mime=getMimeType(extname) res.setHeader('Content-Type', mime+";charset='utf-8'"); res.statusCode=200; res.end(data) } } catch (error) { }}let server = () => { let G = { _get:{}, _post:{}, staticPath:'static' //默认静态web目录 }; let app = function (req, res) { //扩展res的方法 changeRes(res); //配置静态web服务 initStatic(req, res,G.staticPath); let pathname = url.parse(req.url).pathname; //获取请求类型 let method=req.method.toLowerCase(); if (G['_'+method][pathname]) { if(method=="get"){ G['_'+method][pathname](req, res); //执行方法 }else{ //post 获取post的数据 把它绑定到req.body let postData = ''; req.on('data',(chunk)=>{ postData+=chunk; }) req.on('end',()=>{ req.body=postData; G['_'+method][pathname](req, res); //执行方法 }) } } else { res.writeHead(404, { 'Content-Type': 'text/html;charset="utf-8"' }); res.end('页面不存在'); } } //get请求 app.get = function (str, cb) { //注册方法 G._get[str] = cb; } //post请求 app.post = function (str, cb) { //注册方法 G._post[str] = cb; } //配置静态web服务目录 app.static=function(staticPath){ G.staticPath=staticPath; } return app;}module.exports = server();
十二 注册用户并存入数据库- ejs
- mongodb
- fs
- querystring
.server.js
const http=require("http")const app=require('./module/route')//上面封装的const ejs=require('ejs')const qs=require('querystring')const MOngoClient=require('mongodb').MongoClientconst test=require('assert')const url='mongodb://127.0.0.1:27017'const dbName='mydata'http.createServer(app).listen(3000)//首页app.get('/',(req,res)=>{ ejs.renderFile("./views/index.html",{},(err,data)=>{ res.send(data) })})app.get('/register',(req,res)=>{ ejs.renderFile("./views/register.ejs",{},(err,data)=>{ res.send(data) })})//获取注册用户列表app.get('/userlist',(req,res)=>{ MongoClient.connect(url, function(err, client) { test.equal(null, err); const db = client.db(dbName) console.log('链接数据库成功') db.collection("users").find().toArray((err,result)=>{ test.equal(null, err); ejs.renderFile("./views/userlist.ejs",{ users:result },(err,data)=>{ res.send(data) console.log('获取成功') client.close() }) }) }); })//提交注册app.post('/submit',(req,res)=>{ let body=qs.parse(req.body) MongoClient.connect(url, function(err, client) { test.equal(null, err); const db = client.db(dbName) console.log('链接数据库成功') db.collection("users").insertOne( body, (err,result)=>{ test.equal(null,err) console.log('注册成功!') res.send('注册成功!') client.close(); } ) });})