npm
介绍
NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种:
- 允许用户从NPM服务器下载别人编写的第三方包到本地使用。
- 允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用。
- 允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用。
网站
npmjs.com 网站 是用来搜索npm包的
npm命令行工具
npm也有版本概念,可以通过npm –version来查看npm的版本
升级npm(自己升级自己):
1
| npm install --global npm
|
常用命令
package.json
每一个项目都要有一个package.json
文件(包描述文件,就像产品的说明书一样)
这个文件可以通过npm init
自动初始化出来
对于目前来讲,最有用的是dependencies
选项,可以用来帮助我们保存第三方包的依赖信息。
如果node_modules
删除了也不用担心,只需要在控制面板中npm install
就会自动把package.json
中的dependencies
中所有的依赖项全部都下载回来。
- 建议每个项目的根目录下都有一个
package.json
文件
- 建议执行
npm install
包名的时候都加上--save
选项,目的是用来保存依赖信息
package.json和package-lock.json
npm 5以前是不会有package-lock.json
这个文件
npm5以后才加入这个文件
当你安装包的时候,npm都会生成或者更新package-lock.json
这个文件
package.json用处
提升下载速度
package-lock.json
node_modules
1 2 3 4 5 6 7 8
| 中所有包的信息(版本,下载地址。。。)
- 这样的话重新`npm install`的时候速度就可以提升
#### 锁定版本号
- 从文件来看,有一个
|
lock
1 2 3 4 5 6 7 8
|
称之为锁
- 这个`lock`使用来锁版本的 - 如果项目依赖了`1.1.1`版本 - 如果你重新install其实会下载最新版本,而不是`1.1.1` - `package-lock.json`的另外一个作用就是锁定版本号,防止自动升级
|
Express
案例:express留言板、学生信息增删改
简介
Express 是一个简洁而灵活的 Node.JS Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具。
使用 Express 可以快速地搭建一个完整功能的网站。
Express 框架核心特性:
- 可以设置中间件来响应 HTTP 请求。
- 定义了路由表用于执行不同的 HTTP 请求动作。
- 可以通过向模板传递参数来动态渲染 HTML 页面。
安装
1 2 3
| npm init //生成说明文件 npm install --save express
|
简单使用
- 引包
- 创建服务器应用程序
- 接受请求,返回响应
- 发布服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| var express = require('express')
var app = express()
app.use('/public', express.static('./public/'))
app.get('/', function(req,res) { res.send('成功啦!') })
app.listen('3000', function() { console.log('server is running...') })
````
## art-template ### 安装 ```Shell
npm install --sava art-template npm install -save express-art-template
|
配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| app.engine('html', require('express-art-template')) app.set('/views', './views/') ```` ### 使用 ```Javascript
res.render('index.html', { students: students.students }) ```` ## 初识(数据渲染) ```Javascript
var express = require('express') var fs = require('fs')
var app = express()
app.use('/public', express.static('./public/')) app.use('/node_modules/', express.static('./node_modules/'))
app.engine('html', require('express-art-template')) app.set('/views', './views/')
app.get('/', function(req, res) { fs.readFile('db.json', 'utf8', function(err, data) { if (err) { return console.log('数据有误') } var students = JSON.parse(data) res.render('index.html', { students: students.students }) }) })
app.listen(3000, function() { console.log('server is running...') })
|
express-session
官方文档:https://github.com/expressjs/session
安装
配置
- 该插件会为req请求对象添加一个成员:req.session默认是一个对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
app.use(session({ secret: 'dong yi', resave: false, saveUninitialized: false cookie: { secure: true } })) ````
### 使用 ```Javascript
//写 //添加Session数据 //session就是一个对象 req.session.foo = 'bar';
//读 //获取session数据 req.session.foo
//删 req.session.foo = null; delete req.session.foo //推荐
|
其它
session
:保存登录选项,🔺在内存中存储
cookie
:保存不敏感数据
🔺异步编程
得到函数内部异步操作的结果
回调函数:通过一个函数,获取函数内部的操作。(根据输入得到输出结果)
在该情况下无法获得函数内异步操作的结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| function get(a, b) { console.log(a + b) setTimeout(function() { console.log(2) ret = a + b return ret }, 6000); console.log(3) }
console.log(get(20,30)) ```` 结果:返回`undefined`
+ 若要获得该数据则只能通过回调函数 ```Javascript
function get(a, b, c) { console.log(a + b) setTimeout(function() { console.log(2) ret = a + b return c(ret) }, 6000); console.log(3) }
// console.log(get(20,30))
get(20, 30, function(a) { console.log(a) })
|
注意:
凡是需要得到一个函数内部异步操作的结果(setTimeout,readFile,writeFile,ajax,readdir)
这种情况必须通过 回调函数 (异步API都会伴随着一个回调函数)
回调地狱
啥是回调地狱
就是这幅图
为什么会有回调地狱
回调地狱的原因是,当人们试图以一种从上到下的视觉方式执行JavaScript的方式编写JavaScript时。期望第1行发生的任何事情都会在第2行的代码开始运行之前完成,但是,在JavaScript上,有时候这并没办法进行,比如,在你通过异步读取文件时,也就是用fs模块读取多个文件时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| var fs = require('fs')
fs.readFile('./a.txt', 'utf8', function(err, data) { if (err) { console.log(err) } console.log(data) })
fs.readFile('./b.txt', 'utf8', function(err, data) { if (err) { console.log(err) } console.log(data) })
fs.readFile('./c.txt', 'utf8', function(err, data) { if (err) { console.log(err) } console.log(data) })
|
执行多次后,你会发现,有那么几次,也有可能好几次,看人品吧反正是,它是没有规则的读出来的(往往可能你的文件越大,读出来的时间会更久),也就是说,它并不会按照代码书写顺序去执行,这便是异步编程(如果试了没有,那就一直试,反正总会有的)。异步API导致了代码并不是按顺序执行的(可以读读这篇文章 https://www.jianshu.com/p/39adf6ab8ad1 ——然后嘞,就会有上面那种解决方法,但是你会发现,代码非常的丑(别人是这样说的,反正我不是太这么认为,甚至觉得有点好看),还有非常难维护(这点认同)。所以就出现了几种解决方法 —Promise
Promise
Promise:承诺,保证
Promise本身不是异步的,但往往都是内部封装一个异步任务
丢出一张图形容Promise函数,相当于一个容器(下图源于所学教程,pending(悬而未决的))
代码如下,较易维护
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| var fs = require('fs')
var p1 = new Promise(function(resolved, rejected) { fs.readFile('./a.txt', 'utf8', function(err, data) { if (err) { rejected(err) } resolved(data) }) })
var p2 = new Promise(function(resolved, rejected) { fs.readFile('./b.txt', 'utf8', function(err, data) { if (err) { rejected(err) } resolved(data) }) })
var p3 = new Promise(function(resolved, rejected) { fs.readFile('c.txt', function(err, data) { if (err) { rejected(err) } resolved(data) }) })
p1 .then(function(data) { console.log(data) return p2 }) .then(function(data) { console.log(data) return p3 }).then(function(data) { console.log(data) }, function(err) { console.log(err) })
|
then函数(ES6)说明:
封装Promise中的readFile
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| var fs = require('fs')
var pReadFile = function(filepath) { return new Promise(function(resolved, rejected) { fs.readFile(filepath, 'utf8', function(err, data) { if (err) { rejected(err) } resolved(data) }) }) }
pReadFile("a.txt") .then(function(data) { console.log(data) return pReadFile("b.txt") }) .then(function(data) { console.log(data) return pReadFile("c.txt") }).then(function(data) { console.log(data) }, function(err) { console.log(err) })
```` ## Promise应用场景 ### 解决客户端回调嵌套问题 当出现类似于表关联的数据时,这时候就会遇到嵌套问题,当嵌套的数据只有一两个个还好,如果出现三四个甚至五六个,这时候就会出现回调地狱的问题,这里使用promise解决
### 所需知识: 1. npm模块:json-server、http-server 2. 客户端模板引擎art-template 3. Ajax 4. jquery
### 步骤 1. 安装json-server和http-server以及其他必要模块
```Powershell
npm i -g http-server npm i -g json-server npm i jquery --save npm i template --save
|
建立html页面
设计表单,人员信息与工作职业相关联,搭配模板字符串使用
1 2
| <form action="" id="user_form"></form>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <script type="text/template" id="tpl"> <div> <label for="">用户名</label> <input type="text" value="{{ user.username }}"> </div> <div> <label for="">年龄</label> <input type="text" value="{{ user.age }}"> </div> <div> <label for="">职业</label> <select name="" id=""> {{ each jobs }} {{ if user.job === $value.id }} <option value="{{ $value.id }}" selected>{{ $value.name }}</option> {{ else }} <option value="{{ $value.id }}">{{ $value.name }}</option> {{ /if }} {{ /each }} </select> </div> </script>
|
引用相关模板字符串以及JQuery模块
1 2 3
| <script src="node_modules/art-template/lib/template-web.js"></script> <script src="node_modules/jquery/dist/jquery.js"></script>
|
书写Ajax向服务器发起请求,并封装便于使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function get(url, callback) { var oReq = new XMLHttpRequest() oReq.onload = function () { oReq.responseText callback(oReq.responseText) } oReq.open("get", url, true) oReq.send() }
````
6. 开启json-server服务,使用data.json文件(67步使用cmd)
```Powershell json-server data.json
|
将当前文件所处文件夹开放为服务器
- 若采用回调地狱类型
1 2 3 4 5 6 7 8 9 10 11
| get("http://127.0.0.1:3000/users/1",function(userData){ get("http://127.0.0.1:3000/jobs",function(jobsData){ var htmlStr = template("tpl", { user: JSON.parse(userData), jobs: JSON.parse(jobsData) }) console.log(htmlStr) document.querySelector("#user_form").innerHTML = htmlStr }) })
|
- 使用Jquery版的Promise
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
var data = {} $.get("http://127.0.0.1:3000/users/2") .then(function(user){ data.user = user return $.get("http://127.0.0.1:3000/jobs") }) .then(function(jobs){ data.jobs = jobs var str = template("tpl",{ user: data.user, jobs: data.jobs }) document.querySelector('#user_form').innerHTML = str })
````
10. 封装Promise版本的AJAX方法 ```Js
function Rget(url,callback){ return new Promise(function(resolve,reject){ var xhr = new XMLHttpRequest() // 当请求加载成功之后要调用指定的函数 xhr.onload = function () { // 我现在需要得到这里的 xhr.responseText resolve(JSON.parse(xhr.responseText)) callback && callback(JSON.parse(xhr.responseText)) } xhr.onerror = function (err){ reject(err) } xhr.open("get", url, true) xhr.send() }) } ```` + 使用 ```Js
var data = {} Rget("http://127.0.0.1:3000/users/2") .then(function(user){ data.user = user return Rget("http://127.0.0.1:3000/jobs") }) .then(function(jobs){ data.jobs = jobs var str = template("tpl", { user: data.user, jobs: data.jobs }) document.querySelector("#user_form").innerHTML = str })
````
### Promise操作数据库 (26-Promise,Promise操作数据库)
+ mongoose中所有的API都支持promise 🔺根据查询是否已存在该记录从而决定是否创建新记录
```Javascript
Cat.findOne({ name: "好啊" }) .then(function(cat){ if(cat){ console.log('该cat已存在') } else{ return new Cat({"name" : "好啊", "age" : 16 }).save() } }) .then(function(data){ console.log(data) })
```` ### 注意: 1. 每次改完js或html文件后在浏览器需刷新多次 2. 每次改完json文件后需要重新启动json-server服务
### catch异常处理 在全部then之后添加`.catch(err => {})`即可对任何一个then处理过程抛出的异常进行捕获并中止代码继续执行
例如:读取文件并进行后续相关操作,若处理过程发生一个错误则传递给catch,后面所有的then就不再执行
这里要注意区分,如果是在`then`中自行处理`err`,则代码还是会继续往下执行,这是和`catch`不同的点
```Js
readFile('a.txt', 'utf8') .then(data => { console.log(data) return readFile('a.txt', 'utf8') }) .then(data => { console.log(data) }) .catch(err => { console.log(err) })
````
# 中间件 案例:案例5论坛
### 中间件的概念 > 参考文档:http:
中间件:把很复杂的事情分割成单个,然后依次有条理的执行。就是一个中间处理环节,有输入,有输出。
说的通俗易懂点儿,中间件就是一个(从请求到响应调用的方法)方法。
把数据从请求到响应分步骤来处理,每一个步骤都是一个中间处理环节。
同一个请求对象所经过的中间件都是同一个请求对象和响应对象。
## 中间件的分类: ### 应用程序级别的中间件 万能匹配(不关心任何请求路径和请求方法的中间件):
```Javascript
app.use(function(req,res,next){ console.log('Time',Date.now()); next(); }); ```` 关心请求路径和请求方法的中间件:
```Javascript
app.use('/a',function(req,res,next){ console.log('Time',Date.now()); next(); });
```` ## 路由级别的中间件 严格匹配请求路径和请求方法的中间件
get: ```Javascript
app.get('/',function(req,res){ res.send('get'); });
|
post:
1 2 3 4
| app.post('/a',function(req,res){ res.send('post'); });
|
put:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| app.put('/user',function(req,res){ res.send('put'); }); ```` delete:
```Javascript
app.delete('/delete',function(req,res){ res.send('delete'); });
```` ## 错误处理中间件 ```Javascript
app.use(function(err,req,res,next){ console.error(err,stack); res.status(500).send('Something broke'); }); ```` 配置使用404中间件:(论坛案例)
```Javascript
app.use(function(req,res){ res.render('404.html'); });
|
配置全局错误处理中间件: (论坛案例)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| app.get('/a', function(req, res, next) { fs.readFile('.a/bc', funtion() { if (err) { next(err); } }) });
app.use(function(err,req,res,next){ res.status(500).json({ err_code:500, message:err.message }); });
`````
## 内置中间件 + express.static(提供静态文件) * http://expressjs.com/en/starter/static-files.html#serving-static-files-in-express
## 第三方中间件 >参考文档:http://expressjs.com/en/resources/middleware.html
+ body-parser + compression + cookie-parser + mogran + response-time + server-static + session
# art-template搭配dateformat模块 ## 简介 art-template搭配dateFormat实现将时间戳格式化为你想要的日期格式
## 步骤 1. npm下载对应模块
```Bash npm i --save dateformat
|
- 页面代码(注意art-template默认渲染的页面后缀名为art,time为渲染的时间数据,’yyyy-mm-dd’为你要定义的时间格式)
1 2
| 1 {{ dateFormat(time, 'yyyy-mm-dd')}}
|
- node引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| const template = require('art-template'); const path = require('path'); const dateFormat = require('dateformat');
````
4. 配置模板引擎
```Js
template.defaults.imports.dateFormat = dateFormat; ````
5. 渲染页面并打出在cmd控制台
```Js
const html = template('06.art', { time: new Date() }); console.log(html) ````
# 其它 ## nodemon ### 作用 修改完代码自动重启
### 安装 ```Shell
npm install --global nodemon
|
使用
ES6函数
find()
方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined
实现原理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| 1 2 3 4 5 6 7 8 9 10 Array.prototype.findme = function(callback) { for (var i = 0; i < this.length; i++) { if(callback(this[i],i)){ return this[i] } } } console.log(abc.findme(function(item){ return item.id = 3 })) ```` ### findIndex() 返回数组中满足提供的测试函数的第一个元素的索引
## 隐藏元素控件 用来放一些不希望被用户看见,但是需要被提交到服务端的数据
```Html
<input type="hidden" name="id" value="{{ student.id }}">
|