Node.js是什么
-
Node.js® is a JavaScript runtime built on Chrome’s V8 JavaScript engine.
- Node.js不是一门语言
- Node.js不是库、不是框架
- Node.js是一个JavaScript代码
- 简单点来说就是Node.js可以解析和执行JavaScript代码
- 以前只有浏览器可以解析执行JavaScript代码
- 也就是说现在的JavaScript可以完全脱离浏览器来运行,一切都归功于Node.js
-
浏览器中的JavaScript
- EcmaScript
- 基本的语法
- if
- var
- function
- Object
- BOM
- DOM
- EcmaScript
-
Node.js 中的JavaScript
- 没有 BOX DOM
- EcmaScript
- 在Node这个JavaScript执行环境中为JavaScript提供了一些服务器级别的操作API
- 例如在文件读写
- 网络服务的构建
- 网络通讯
- http服务器
- 等等。。。
-
构建在Chrome的V8引擎之上
- 代码只是具有特定格式的字符串
- 引擎可以认识它,引擎可以帮你去解析和执行
- Google Chrome的V8引擎是目前公认的解析执行JavaScript代码最快的
-
Node.js uses an eventt-driven, non-blocking I/O model that makes it lightweight and efficient
- event-driven 事件驱动
- non-blocking I/O model 非阻塞IO模型
- lightweight and efficient轻量和高效
-
Node.js’ package ecosystem, npm, is the largest ecosystem of open source libaraies in the world.
- npm 是世界上最大的开源生态系统
- 绝大多数JavaScript相关的包都放在了npm上,这样做的目的是为了让开发人员更方便的去下载使用
npm install jquery
Node.js能做什么
-
Web服务器后台
-
命令行工具
- npm(node)
- git(c语言)
- hexo(node)
- …
-
对于前端开发工程师,接触node最多的是他的命令行工具
- webpack
- gulp
- npm
预备知识
-
HTML
-
CSS
-
JavaScript
-
简单的命令行操作
- cd
- dir
- ls
- mkdir
- rm
-
具有服务器开发经验更佳
能学到什么?
- B/S编程模型
- Browser - Server
- back-end
- 任何服务端技术这种BS编程模型都是一样的
- node 只是作为学习BS编程模型的一个工具
- 模块化编程
- RequireJS
- SeaJs
@import('文件路径')
- 在Nide中可以像
@import
一样来引用加载JavaScript脚本文件
- Node常用API
- 异步编程
- 回调函数
- Promise
- async
- generator
- Express Web 开发框架
- Ecmascript 6
Hello World
1.创建编写JavaScript脚本文件
2.打开终端定位到脚本文件的目录
3.输入 node 文件名
执行对应的文件
注意:文件名不要使用 node.js
命名
-
解析执行 JavaScript
-
读写文件
-
http
-
最简单的 http 服务:
// 使用 node 构建一个 Web 服务器 // 在 node 中提供了一个核心模块:http // http 这个模块的职责是帮你创建编写服务器 // 1.加载 http 核心模块 var http = require('http'); // 2.使用 http.createServer() 方法创建一个 Web 服务器 // 返回一个Server实例 var server = http.createServer(); // 3.服务器提供对数据的服务 /*发请求 * 接收请求 * 处理请求 * 给个反馈(发送响应) * 注册 requset 请求事件 * 当客户端请求过来,就会自动触发服务器的 request 请求事件,然后执行第二个参数:回调处理函数 */ server.on('request', function () { console.log('收到客户端请求'); }) // 4.绑定端口号,启动服务器 server.listen(3000, function () { console.log('服务器启动成功,可以通过 http://127.0.0.1:3000/ 访问') });
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jEpmIFDF-1575955038352)(C:\Users\89349\AppData\Roaming\Typora\typora-user-images\1574495523937.png)]
Node 中的JavaScript
- EcmaScript
- 没有 DOM、BOM
- 核心模块
- 第三方模块
- 用户自定义模块
核心模块
node 为 JavaScript 提供了很多服务器级别的 API,这些 API 绝大多数都被包装到了一个具名的核心模块中。
例如:文件操作的 fs
核心模块,http 服务构建的 http
模块,path
路径操作模块,os
操作系统信息模块。
只要说这个模块是一个核心模块,就必须要使用它
var fs = require('fs')
var http = require('http')
Web 服务器开发
ip 地址和端口号
- ip 地址用来地位计算机
- 端口号用来定给我具体得应用程序
- 一切需要联网的软件都会占用一个端口号
- 端口号的范围是 0 - 65536
- 在计算机中有一些默认端口号,最好不要去使用
- http服务的 80
Content-Type
http://tool.oschina.net/
请求对象 Request
响应对应 Response
在 Node 中使用模板引擎
统一处理静态资源
服务端渲染和客户端渲染的区别
- 客户端渲染不利于 SEO 搜索引擎优化
- 服务端渲染是可以被爬虫抓取到的,客户端异步渲染很难被爬虫抓取到
- 所以真正的网站既不是纯异步也不是纯服务端渲染的,两者相结合
- 例如:京东的商品列表就是采用的服务端渲染,目的是为了 SEO 搜索引擎优化
- 而商品评论列表是客户端端渲染,它不需要 SEO 优化,更是为了用户体验
node 中的模块系统
使用 node 编写应用程序主要使用:
- EcmaScript 语言
- 和浏览器不一样,在 Node 中没有 BOM、DOM
- 核心模块
- 文件操作的 fs
- http 服务的 http
- url 路径操作模块
- path 路径操作模块
- os 操作系统信息
- 第三方模块
- art-template
- 必须通过 npm 下载
- 自己写的模块
- 自己创建的文件
什么是模块化
- 文件作用域
- 通信规则
- 加载 require
- 导出
CommonJS 模块规范
在 node 中的 JavaScript 还有一个重要的概念:模块系统
- 模块作用域
- 使用 require 方法来加载模块
- 使用 exports 接口对象用来导出模块中的成员
加载 require
语法:
var 自定义变量名称 = require('模块');
两个作用:
- 执行被加载模块中的代码
- 得到被加载模块中的
exports
导出接口对象
导出 exports
-
node 中是模块作用域,默认文件中所有的成员只在当前文件
-
对于希望可以被其他模块访问的成员,我们就需要把这些公开的成员都挂载到
exports
接口对象中就可以了
导出多个成员(必须在对象中):
exports.a = 123;
exports.b = 'hello';
exports.c = function () {
console.log('ccc');
}
exports.d = {
foo : 'bar'
}
导出单个成员(拿到的就是:函数、字符串):
module.exports = 'hello';
以下情况还会覆盖:
// 一个模块需要直接导出某个成员
module.exports = 'hello';
// 后者会覆盖前者
module.exports = function (x, y) {
return x + y;
}
也可以这样导出多个成员:
module.exports = {
add: function (x, y) {
return x + y;
},
str: 'hello'
}
原理解析
exports 和 module.exports
的一个引用
console.log(exports === module.exports); // => true
exports.foo = 'bar';
// 等价于
module.exports.foo = 'bar';
exports 和 module.exports 的区别
-
每个模块中都有一个 module 对象
-
module 对象中有一个 exports 对象
-
我们可以把需要导出的成员都挂载到 module.exports 接口对象中
-
也就是:
moudle.exports.xxx = xxx
的方式 -
但是每次都
moudle.exports.xxx = xxx
很麻烦,点儿的太多了 -
所以 Node 为了你方便,同时在每一个模块中都提供了一个成员叫:
exports
-
exports === module.exports
结果为true
s -
所以对于:
moudle.exports.xxx = xxx
的方式 完全可以:expots.xxx = xxx
-
当一个模块需要导出单个成员的时候,这个时候必须使用:
module.exports = xxx
的方式 -
不要使用
exports = xxx
不管用 -
因为每个模块最终向外
return
的是module.exports
-
而
exports
只是module.exports
的一个引用 -
所以即便你为
exports = xx
重新赋值,也不会影响module.exports
-
但是有一种赋值方式比较特殊:
exports = module.exports
这个用来重新建立引用关系的 -
之所以让大家明白这个道理,是希望可以更灵活的去用它
-
Node 是一个比肩 Java、PHP 的一个平台
- JavaScript 既能写前端也能写服务端
moudle.exports = {
a: 123
}
// 重新建立 exports 和 module.exports 之间的引用关系
exports = module.exports
exports.foo = 'bar'
Array.prototype.mySlice = function () {
var start = 0
var end = this.length
if (arguments.length === 1) {
start = arguments[0]
} else if (arguments.length === 2) {
start = arguments[0]
end = arguments[1]
}
var tmp = []
for (var i = start; i < end; i++) {
// fakeArr[0]
// fakeArr[1]
// fakeArr[2]
tmp.push(this[i])
}
return tmp
}
var fakeArr = {
0: 'abc',
1: 'efg',
2: 'haha',
length: 3
}
// 所以你就得到了真正的数组。
[].mySlice.call(fakeArr)
require 方法加载规则
-
核心模块
- 模块名
-
第三方模块
- 模块名
-
用户自己写的
- 路径
-
优先从缓存中加载
-
判断模块标识符
- 核心模块
- 第三方模块
- 自己写的模块
blog
a
node_modules
b
main.js
// b 加载不到 node_modules
npm
- node package manager
npm 网站
npmjs.com
npm 命令行工具
npm 的第二层含义就是一个命令行工具,只要安装了 node 就已经安装了 node。
npm 也有版本概念。
可以通过在命令行输入:
npm --version
升级 npm:
npm install --global npm
npm 常用命令
-
npm init
- npm int -y 可以跳过向导,快速生成
-
npm install
- 一次性把 dependencies 选项中的依赖项全部安装
-
npm install 包名
- 只下载
- npm i 包名
-
npm install --save
- 下载并且保存依赖项(package.json 文件中的 dependencies 选项)
- npm i -S 包名
-
npm uninstall 包名
- 只删除,如果有依赖项,会保存依赖项
- npm un 包名
-
npm uninstall --save 包名
- 删除的同时也会把依赖信息删除
- npm un -S 包名
-
npm help
- 查看使用帮助
-
npm 命令 --help
- 查看指定命令的使用帮助
- 例如忘记了 uninstall 命令的简写,这个时候,可以输入
npm uninstall --help
来查看使用帮助
解决 npm 被墙问题
npm 存储包文件的服务器在国外,有时候会被墙,速度很慢,所以我们需要解决。
http://npm.taobao.org/ 淘宝的开发团队把 npm 在国内做了一个备份。
安装淘宝的 cnpm:
# 在任意目录下执行都可以
# --global 表示安装到全局
# --global 不能省略
npm install --global cnpm
接下来你安装包的时候把之前的 npm
替换成 cnpm
。
举个例子:
# 这里还是走国外的 npm 服务器,速度比较慢
npm install jquery
# 使用 cnpm 就会通过淘宝的服务器来下载 jquery
cnpm install jquery
如果不想安装 cnpm
又想使用淘宝的服务器来下载:
npm install jquery --registry=https://registry.npm.taobao.org
每次添加参数和麻烦,可以把这个选项添加到配置文件中:
npm config set registry https://registry.npm.taobao.org
# 查看 npm 配置信息
npm config list
只要经历了上面的命令配置,则以后所有的 npm install
都会默认通过淘宝的服务器来下载。
package.json
我们建议每一个项目都要有一个 package.json
文件(包描述文件,就像产品的说明书一样)
这个文件可以通过 npm init
的方式来自动初始化出来。 直接生成(npm init -y
)
PS H:\前端-19\14nodejs(7天)\mytest_node\day03\npm-pack> npm init This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help json` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (npm-pack)
version: (1.0.0) 0.0.1
description: 这是一个测试项目
entry point: (index.js) main.js
test command:
git repository:
keywords:
author: Mr.Zhang
license: (ISC)
About to write to H:\前端-19\14nodejs(7天)\mytest_node\day03\npm-pack\package.json:
{
"name": "npm-pack",
"version": "0.0.1",
"description": "这是一个测试项目",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Mr.Zhang",
"license": "ISC"
}
Is this OK? (yes) yes
PS H:\前端-19\14nodejs(7天)\mytest_node\day03\npm-pack> npm install --save jquery
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN npm-pack@0.0.1 No repository field.
+ jquery@3.4.1
added 1 package from 1 contributor and audited 1 package in 13.807s
found 0 vulnerabilities
对于我们来讲,最有用的就是 dependencies
选项,可以用来帮助我们保存第三方包的依赖信息。
如果你的 node_modules
删除了也不必担心,只需要:npm install
就会自动把 package.json
中的 dependencies
中的所有的依赖项都下载下来。
- 建议每个项目的根目录下都有一个
package.json
文件 - 建议执行
npm install 包名
的时候都加上--save
用来保存依赖项信息
package.json和 package-lock.json
npm5 以前没有 package-lock,json
这个文件。
npm5 以后才加入了这个文件。
当你安装包的时候, npm 都会生成或更新 package-lock.json
这个文件。
-
npm5 以后的版本安装包不需要加
--save
参数,它会自动保存依赖信息。 -
当你安装包的时候,会自动创建或者更新
package-lock.json
这个文件。 -
package-lock.json
这个文件会保存node_modules
中所有包的信息(版本、下载地址)- 重新安装的话会加快安装速度
npm install
- 重新安装的话会加快安装速度
-
从文件来看,有一个
lock
称之为锁- 这个
lock
是为了锁定版本 - 如果项目依赖了
1.1.1
版本 - 如果你重新 install 其实会下载最新版本
- 我们的目的是希望可以锁住
1.1.1
这个版本 - 所有这个
package-lock.json
这个文件的另一个左右就是锁定版本号,防止升级成新版本
- 这个
path 路径操作模块
- path.basename
- 获取一个路径的文件名(默认包含扩展名)
- path.dirname
- 获取一个路径中的目录部分
- path.extname
- 获取一个路径中的扩展名部分
- path.parse
- 把一个路径转换为对象
- root 根路径
- dir 目录
- base 包含后缀名的文件名
- ext 后缀名
- name 不包含后缀名的文件名
- 把一个路径转换为对象
- path.join
- 路径拼接
- path.isAbsolute
- 判断一个路径是否为绝对路径
node 中的其他成员
在每个模块中,除了 require
、exports
等模块相关 API 之外,还有两个特殊的成员:
__dirname
动态获取 可以用来获取当前文件模块所属目录的绝对路径__filename
动态获取 可以用来获取当前文件的绝对路径__dirname
和__filename
不受执行 node 命令所属路径影响的
在文件操作中,使用相对路径不可靠,以为在 node 中文件操作的路径被设计为相对于对于执行 node 命令所处的路径(不是 bug)。
为了解决这个问题,使用绝对路径。
使用 __dirname
或者 __filename
来帮助解决问题。
结合 path.join()
path.join(__dirname, './a.txt')
补充:模块的路径标识和这里的路径没有关系
Express
原生的 http 在某些方面表现不足以应对我们的开发需求,所以我们使用框架来加快我们的开发效率,框架的目的就是提高效率,让我们的代码高度统一。
在 node 中,有很多 Web 开发框架,学习 express
为主。
- http://expressjs.com/
起步
安装:
npm install --save express
hello world
var express = require('express');
// 1. 创建 app
var app = express();
app.get('/', function (req, res) {
// res.write('hello ');
// res.write('你好');
// res.end();
// res.end('hello world');
res.send('hello world');
// res.send('hello 你好');
})
app.listen(3000, function () {
console.log('express running·····');
});
基本路由
路由器
- 请求方法
- 请求路径
- 请求处理函数
get:
// 当你以 get 方法请求 / 的时候,执行对应的处理函数
app.get('/', function (req, res) {
res.send('Hello World!')
})
post:
// 当你以 post 方法请求 / 的时候,执行对应的处理函数
app.post('/', function (req, res) {
res.send('Hello World!')
})
静态服务
// 当以 /public/ 开头的时候,去 ./public/ 目录中去找对应的资源
app.use('/public', express.static('./public/'));
//
// 当省略第一个参数的时候,则可以通过省略 /public 的方式访问
app.use(express.static('./public/'));
//
// 必须是 /a/public目录中的资源名称
// a 相当于 public 的别名
app.use('/a', express.static('./public/'));
app.use('/public', express.static(path.join(__dirname, 'public')))
在 Express 中配置使用 art-template
模板引擎
安装:
npm install --save art-template
npm install --save express-art-template
配置:
app.engine('html', require('express-art-template'));
使用:
app.get('/', function (req, res) {
// express 默认会去项目中的 views 目录中找 index.html
res.render('index.html', {
title: 'hello'
})
})
如果希望修改默认的 views
视图渲染存储目录,可以:
// 注意:第一个参数 views 不能写错
app.set('views', 目录路径)
在 Express 中获取表单 GET 请求参数
Express 内置了一个 API,可以直接通过 req.query
来获取。
req.query
在 Express 中获取表单 POST 请求体数据
在 Express 中没有内置获取表单 POST 请求体的 API,我们需要使用一个第三方包:body-parser
。
安装:
npm install --save body-parser
配置:
var express = require('express')
// 1. 引包
var bodyParser = require('body-parser')
var app = express()
// 配置 body-parser
// 只要加入这个配置,则在 req 请求对象上会多出来一个属性:body
// 通过 req.body 来获取表单 POST 请求体数据
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
使用:
app.use(function (req, res) {
res.setHeader('Content-Type', 'text/plain')
res.write('you posted:\n')
// 可以通过 req.body 来获取表单 POST 请求体数据
res.end(JSON.stringify(req.body, null, 2))
})
在 Express 配置使用 express-session
插件
参考文档:https://www.npmjs.com/package/express-session
安装:
npm install express-session
配置:
// 在 Express 这个框架中,默认不支持 Session 和 Cookie
// 但是我们可以使用第三方中间件:express-session 来解决
// 1. npm install express-session
// 2. 配置(一定要在路由挂载之前)
// 3. 使用
// 当把这个插件配置好之后,我们就可以通过 req.session 来访问和设置 session 成员
// 添加 session 数据 req.session.foo = 'bar'
// 访问 session 数据 req.session.foo
app.use(session({
// 配置加密字符串 --- 会在原有加密基础上和这个字符串拼接起来加密
// 目的是为了增强安全性,防止客户端恶意伪造
secret: 'keyboard cat',
resave: false,
saveUninitialized: true // 无论你是否使用 session,我都直接给你分配一把钥匙
}))
使用:
// 添加 session 数据
req.session.foo = 'bar'
// 获取 session 数据
req.session.foo
提示:默认 session 数据是内存存储的,服务器一旦重启就会丢失,真正的生产环境会把 session 进行持久化存储。
CRUD案例
起步
- 初始化
- 安装依赖
- 模板处理
路由设计
请求方法 | 请求路径 | get 参数 | post 参数 | 备注 |
---|---|---|---|---|
GET | /students | 渲染首页 | ||
GET | /students/new | 渲染添加学生页面 | ||
POST | /students/new | name、age、gender、hobbies | 处理添加学生请求 | |
GET | /students/edit | id | 渲染编辑页面 | |
POST | /students/edit | id、name、age、gender、hobbies | 处理编辑请求 | |
GET | /students/delete | id | 处理删除请求 |
提取路由模块
router.js:
/**
* router.js 路由模块
* 职责:
* 处理路由
* 根据不同的请求方法+请求路径设置具体的请求处理函数
*/
var fs= require('fs')
// Express 提供了一种更好的方式
// 专门用来包装路由的
var express = require('express')
// 1. 创建一个路由容器
var router = express.Router()
// 2. 把路由都挂载到 Router 容器中
router.get('/students', function (req, res) {
// readFile 的第二个参数是可选的,传入 utf8 就是告诉他把读取到的文件直接按照 utf8 编码转成我们能认识的字符
// 除了这样来转换之外,也可以通过 data.toString() 的方式
fs.readFile('./db.json', 'utf8', function (err, data) {
if (err) {
return res.status(500).send('Server error')
}
// 从文件中读取到的数据一定是字符串
// 所以这里一定要手动转换成对象
var students = JSON.parse(data).students
res.render('index.html', {
fruits: [
'苹果',
'香蕉',
'火龙果'
],
students: students
})
})
})
router.get('/students/new', function (req, res) {
res.render('new.html')
})
router.post('/students/new', function (req, res) {
// 1. 获取表单数据
// 2. 处理
// 将数据保存到 db.json,持久化
// 3. 发送响应
// 先读取出来,转成对象
// 然后往对象中 push 数据
// 然后把对象转为字符串
// 然后把字符串再次写入文件
console.log(req.body)
})
router.get('/students/edit', function (req, res) {
})
router.post('/studens/edit', function (req, res) {
})
router.get('/students/delete', function (req, res) {
})
// 3. 把 router 导出
module.exports = router
app.js:
var router = require('./router')
// 挂载路由
app.use(router)
设计操作数据的 API 文件模块
student.js:
/**
* student.js
* 数据操作文件模块
* 职责:操作文件中的数据,只处理数据,不关心业务
*/
/**
* 获取所有学生列表
* return []
*/
exports.find = function () {
}
/**
* 添加保存学生
*/
exports.save = function () {
}
/**
* 更新学生
*/
exports.update = function () {
}
/**
* 删除学生
*/
exports.delete = function () {
}
MongoDB
关系型数据库和非关系型数据库
表与表之间存在关系
- 所有的关系型数据库都需要通过
sql
语言来操作 - 所有关系型数据库在操作之前都需要设计表结构
- 数据表还支持约束
- 唯一的
- 主键
- 默认值
- 非空
- 非关系型数据库非常灵活
- 有的非关系型数据库就是 key-value 键值对
- MongoDB 是长得最像关系型数据库的非关系型数据库
- 数据库 -> 数据库
- 数据表 -> 集合(集合)
- 表记录 -> 文档对象
- MongoDB 不需要设计表结构
- 可以任意的往里面存放数据,没有结构
安装
-
64位下载地址:https://www.mongodb.com/download-center/community
-
下载
-
安装
-
配置环境变量
-
输入
mongod --version
测试是否安装成功[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p4zXKNiW-1575955038354)(C:\Users\89349\AppData\Roaming\Typora\typora-user-images\1575610504849.png)]
启动和关闭数据库
启动:
# mongodb 默认使用执行 mongod 命令所处盘符根目录下的 /data/db 作为自己的数据存储目录
# 所以在第一次执行该命令之前先自己手动新建一个 /data/db
mongod
如果想要修改默认的数据存储目录,可以:
mongod --dbpath=数据存储目录路径
停止:
在开启服务的控制台,直接 ctrl + c 即可停止
或者直接关闭开启服务的控制台
连接数据库
连接:
# 该命令默认连接本机的 mongodb 服务
mongo
退出:
# 在连接状态输入
exit
基本命令
-
show dbs
- 查看显示所有数据库
-
db
- 查看当前操作的数据库
-
use 数据库名称
- 切换到指定的数据库(如果没有,新建一个数据库)
-
插入数据
在 node 中如何操作 MongoDB 数据
使用官方的 mongodb
包使用
https://www.npmjs.com/package/mongodb
使用 mongoose 来操作 MongoDB 数据库
第三方包:mongoose
基于 MongoDB 官方的 mongodb
包做了封装
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
const Cat = mongoose.model('Cat', { name: String });
const kitty = new Cat({ name: 'Zildjian' });
kitty.save().then(() => console.log('meow'));
mongoose 操作数据库流程 案例
var mongoose = require('mongoose')
var Schema = mongoose.Schema
// 1. 连接数据库
mongoose.connect('mongodb://localhost/itcast');
// 2. 设计文档结构(表结构)
// 字段名称就是表结构中的属性名称
// 值
// 约束的目的是为了保证数据的完整性,不要有脏数据
var userSchema = new Schema({
username: {
type: String,
required: true // 不能为空
},
password: {
type: String,
required: true
},
email: {
type: String
}
});
// 3. 将文档结构发布为模型
// mongoose.model 方法就是用来将一个架构发布为 model
// 第一个参数:传入一个大写名词单数字符串用来表示你的数据库名称
// mongoose 会自动将大写名称的字符串生成 小写复数 的集合名称
// 例如 User ---> users
// 第二个参数:构架 Schema
//
// 返回值:模型构造函数
var User = mongoose.model('User', userSchema)
// 4. 当我们有了模型构造函数之后,就可以使用这个构造函数对 users 集合中的数据进行 增、删、改、查
/**
* 新增数据
* @type {User}
*/
var admin = new User({
username: 'root',
password: '789',
email: 'root@root.com'
})
admin.save(function (err, ret) {
if (err) {
console.log('保存失败')
} else {
console.log('保存成功')
console.log(ret)
}
})
// =====================================================
/**
* 查询所有数据
* @param {[type]} err [description]
* @param {[type]} ret) { if (err) { console.log('查询失败') } else { console.log(ret) }} [description]
* @return {[type]} [description]
*/
User.find(function (err, ret) {
if (err) {
console.log('查询失败')
} else {
console.log(ret)
}
})
/**
* 按照条件查询
* @param {[type]} err [description]
* @param {[type]} ret) { if (err) { console.log('查询失败') } else { console.log(ret) }} [description]
* @return {[type]} [description]
*/
User.find({
username: 'root'
},function (err, ret) {
if (err) {
console.log('查询失败')
} else {
console.log(ret)
}
})
/**
* 查询第一个符合条件的数据,数据类型是----对象
* @param {[type]} err [description]
* @param {[type]} ret) { if (err) { console.log('查询失败') } else { console.log(ret) }} [description]
* @return {[type]} [description]
*/
User.findOne({
username: 'admin'
},function (err, ret) {
if (err) {
console.log('查询失败')
} else {
console.log(ret)
}
})
// =====================================================
/**
* 删除数据(按条件)
* @param {[type]} err [description]
* @param {[type]} ret) { if (err) { console.log('删除失败') } else { console.log('删除成功') console.log(ret) }} [description]
* @return {[type]} [description]
*/
User.remove({
username: 'root'
},function (err, ret) {
if (err) {
console.log('删除失败')
} else {
console.log('删除成功')
console.log(ret)
}
})
// =====================================================
/**
* 更新数据(按条件)
* @param {[type]} err [description]
* @param {[type]} ret) { if (err) { console.log('更新失败') } else { console.log('更新成功') console.log(ret) }} [description]
* @return {[type]} [description]
*/
User.findByIdAndUpdate('5deb06ead567bd38505d5db3', {
password: 'what'
}, function (err, ret) {
if (err) {
console.log('更新失败')
} else {
console.log('更新成功')
console.log(ret)
}
})
Promise
callback hell
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-piwFgZUP-1575955038354)(C:\Users\89349\Desktop\u=2529250617,3283018274&fm=26&gp=0.jpg)]
无法保证顺序的代码
var fs = require('fs')
fs.readFile('./data/a.txt', 'utf8', function (err, data) {
if (err) {
// return console.log('读取失败')
// 抛出异常
// 1. 阻止程序的执行
// 2. 把错误消息打印到控制台
throw err
}
console.log(data)
})
fs.readFile('./data/b.txt', 'utf8', function (err, data) {
if (err) {
// return console.log('读取失败')
// 抛出异常
// 1. 阻止程序的执行
// 2. 把错误消息打印到控制台
throw err
}
console.log(data)
})
fs.readFile('./data/c.txt', 'utf8', function (err, data) {
if (err) {
// return console.log('读取失败')
// 抛出异常
// 1. 阻止程序的执行
// 2. 把错误消息打印到控制台
throw err
}
console.log(data)
})
通过回调嵌套的方式来保证代码的执行顺序
var fs = require('fs')
fs.readFile('./data/a.txt', 'utf8', function (err, data) {
if (err) {
// return console.log('读取失败')
// 抛出异常
// 1. 阻止程序的执行
// 2. 把错误消息打印到控制台
throw err
}
console.log(data)
fs.readFile('./data/b.txt', 'utf8', function (err, data) {
if (err) {
// return console.log('读取失败')
// 抛出异常
// 1. 阻止程序的执行
// 2. 把错误消息打印到控制台
throw err
}
console.log(data)
fs.readFile('./data/c.txt', 'utf8', function (err, data) {
if (err) {
// return console.log('读取失败')
// 抛出异常
// 1. 阻止程序的执行
// 2. 把错误消息打印到控制台
throw err
}
console.log(data)
})
})
})
为了解决回调地狱的嵌套,EcmaScript 6 中新增了一个 API:Promise
。
Promise
本身不是异步的。
Promise基本语法
var fs = require('fs')
// EcmaScript 6 中新增了一个 API Promise
// Promise 是一个构造函数
// console.log(1)
// 创建 Promise 容器
// Promise 一旦创建,就开始执行里面的代码
var p1 = new Promise(function (resolve, reject) {
// console.log(2)
fs.readFile('./data/a.txt', 'utf8', function (err, data) {
if (err) {
// 失败了,承诺容器中的任务失败了
// console.log(err)
// 把容器的 Pending 状态变成 Reject
//
// 调用 reject 就相当于调用了 then 方法中的第二个函数
reject(err)
} else {
// console.log(3)
// 承诺容器中的任务成功了
// console.log(data)
// 把容器的 Pending 状态变成 Resolved
// 这里调用的 resolve 方法实际上就是 then 方法传递的那个 function
resolve(data)
}
})
})
var p2 = new Promise(function (resolve, reject) {
fs.readFile('./data/b.txt', 'utf8', function (err, data) {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
var p3 = new Promise(function (resolve, reject) {
fs.readFile('./data/c.txt', 'utf8', function (err, data) {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
// p1 就是那个承诺
// 当 p1 成功了,然后(then)做指定的操作
// then 方法接收的 function 就是容器中的 resolve
p1
.then(function(data) {
console.log(data)
// 当 p1 读取成功的时候
// 当前函数中的 return 的结果就可以在后面的 then 中 function 接收到
// 当你 return 123 后面接收到的就是 123
// 没有return 接收到的就是 undefined
//
// 真正要 return 的是一个 Promise 对象
// 当 return 一个 Promise 对象的时候,后续的 then 中的方法的第一个参数会作为 p2 的 resolve
return p2
}, function(err) {
console.log('读取文件失败了', err)
})
.then(function(data) {
console.log(data)
return p3
}, function(err) {
console.log('读取文件失败', err)
})
.then(function(data) {
console.log(data)
}, function(err) {
console.log('读取文件失败', err)
})
封装 Promise 版本的 readFile
var fs = require('fs')
function pReadFile(filePath) {
return new Promise(function (resolve, reject) {
fs.readFile(filePath, 'utf8', function (err, data) {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
}
pReadFile('./data/a.txt')
.then(function (data) {
console.log(data)
return pReadFile('./data/b.txt')
})
.then(function (data) {
console.log(data)
return pReadFile('./data/c.txt')
})
.then(function (data) {
console.log(data)
})
其他
基于原生 XMLHttpRequest 封装 get 方法
function get(url, callback) {
var oReq = new XMLHttpRequest();
oReq.onload = function(e) {
var arraybuffer = oReq.response; // not responseText
/* ... */
callback(oReq.response)
}
oReq.open("GET", url);
oReq.send();
}
get('data.json', function(data) {
console.log(data)
})
修改完代码自动重启
可以使用第三方工具: nodemon
帮助我们解决频繁修改代码重启服务器的问题。
nodemon
是一个基于 node.js 开发的一个第三方命令行工具,我们使用的时候需要独立安装:
# 在任意目录执行该命令都可以
npm install --global nodemon
安装完毕之后,使用:
node app.js
# 使用 nodemon
nodemon app.js
只要是通过 nodemon app.js
启动的服务,则它会监视你的文件变化,当文件发生变化时,自动帮你重启服务器。
文件操作路径和模块操作路径
文件操作路径:
// 在文件操作的相对路径中
// ./data/a.txt 相对于当前目录
// data/a.txt 相对于当前目录
// /data/a.txt 绝对路径,当前文件模块所处磁盘根目录
// h:/xx/xx.. 绝对路径
fs.readFile('/data/a.txt', function (err, data) {
if (err) {
return console.log(err);
}
console.log(data.toString());
})
模块操作路径:
// 这里的 / 也是磁盘根路径
require('/data/foo.js')
// 相对路径
require('./data/foo.js')
// 模块加载的路径中的相对路径 ./ 不能省略
t(err)
} else {
resolve(data)
}
})
})
}
pReadFile(’./data/a.txt’)
.then(function (data) {
console.log(data)
return pReadFile(’./data/b.txt’)
})
.then(function (data) {
console.log(data)
return pReadFile(’./data/c.txt’)
})
.then(function (data) {
console.log(data)
})
### 其他
***
#### 基于原生 XMLHttpRequest 封装 get 方法
```javascript
function get(url, callback) {
var oReq = new XMLHttpRequest();
oReq.onload = function(e) {
var arraybuffer = oReq.response; // not responseText
/* ... */
callback(oReq.response)
}
oReq.open("GET", url);
oReq.send();
}
get('data.json', function(data) {
console.log(data)
})
修改完代码自动重启
可以使用第三方工具: nodemon
帮助我们解决频繁修改代码重启服务器的问题。
nodemon
是一个基于 node.js 开发的一个第三方命令行工具,我们使用的时候需要独立安装:
# 在任意目录执行该命令都可以
npm install --global nodemon
安装完毕之后,使用:
node app.js
# 使用 nodemon
nodemon app.js
只要是通过 nodemon app.js
启动的服务,则它会监视你的文件变化,当文件发生变化时,自动帮你重启服务器。
文件操作路径和模块操作路径
文件操作路径:
// 在文件操作的相对路径中
// ./data/a.txt 相对于当前目录
// data/a.txt 相对于当前目录
// /data/a.txt 绝对路径,当前文件模块所处磁盘根目录
// h:/xx/xx.. 绝对路径
fs.readFile('/data/a.txt', function (err, data) {
if (err) {
return console.log(err);
}
console.log(data.toString());
})
模块操作路径:
// 这里的 / 也是磁盘根路径
require('/data/foo.js')
// 相对路径
require('./data/foo.js')
// 模块加载的路径中的相对路径 ./ 不能省略