day 5
异步函数 回调函数
同步函数:一行一行的执行代码到函数结束
(function add(a, b) {
return a + b;
})(x, y);
异步编程:不会按一横一行的的执行
想要得到setimeout的结果只能用回调函数
异步函数 永远是在普通代码执行完之后执行
add(1,2) 不会返回结果 只会返回undefined,因为add函数没有异步函数的返回值
例1:
function add(x, y) {
setTimeout(function() {
var ret = x + y;
return ret;
}, 1000)
}
//想要得到setimeout的结果只能用回调函数
//异步函数 永远是在普通代码执行完之后执行
log(add(1,2));//undefined
例2:
function add(x, y) {
var ret;
setTimeout(function() {
ret = x + y;
}, 1000)
return ret;
}
console.log(add(1, 2)); //undefined ret声明了之后跳过异步函数就返回了
回调函数就是为了的到异步编程的结果
如 setTimeout ,readFile ,writeFile,ajax都是异步编程,想要得到异步编程的结果必须用回调函数
callback参数当做参数传入异步函数
//通过回调函数拿异步函数的结果
function add(x, y, callback) {
var ret;
setTimeout(function() {
ret = x + y;
callback(ret);
}, 1000)
}
(add(1, 2, function(ret) {
console.log(ret);
}));
!!通过回调函数 就能够对 异步函数的结果进行运算
这里不能用闭包 因为这是异步操作 ,异步函数永远在最外层函数内的其他代码执行完再执行
Ajax封装
~~封装Ajax 想要的到onload中的结果必须用回调函数
function getAjax(url, callback) {
var Oreq = new XMLHttpRequest;
//当请求调用成功之后调用的函数
Oreq.onload = function() {
callback(Oreq.responseText);
}
Oreq.open("get", url, true);
Oreq.send();
}
getAjax("json.json", function(responseText) {
console.log(responseText);
})
JavaScript模板化问题
JavaScript天生不支持模块化(exports,require) ,只有在Node中才有
模板化:通过API进行文件之间的依赖,模板作用域 ,NODE中支持CommonJS所以可以模板化
不能模板化:通过script src link 等来引用加载,而且必须考虑加载的顺序问题
在浏浏览器中也有几个第三方API提供模块化内容(解决模块化问题):
require.js 第三方库 AMD
sea.js 第三方库CMD
commonJS,AMD,CMD都是民间的api,Ecmascript2016官方标准已经发布,但是很多JavaScript运行环境还不支持
解决方法:
npm5以后下载安装包不需要用--save
就会加入到package-lock.json文件
- 下载express会有一堆文件 因为 express也用到了其他依赖
- lock是用来锁定版本的,当删除了某个安装包如express通过
npm install
下载时会下载锁定的版本
finde和findIndex的底层原理
引用了回调函数的运用也是闭包
var users = [
{ id: 1, name: "a" },
{ id: 2, name: "a" },
{ id: 3, name: "a" },
{ id: 4, name: "a" }
]
//给Array添加方法
//conditionFunc就是写的数组需要满足的条件
Array.prototype.myFind = function(conditionFunc) {
//conditionFunc = (function(term, index) {return term.id = 4;
})
for (var i = 0; i < this.length; i++) {
if (conditionFunc(this[i], i)) {
return this[i]; //将满足条件函数的数组项返回 也可以返回i就是满足条件的数组的index
}
}
}
var ret = myFind(function(term, index) {
return term.id = 4;
})
console.log(ret);
关系型数据库(SQL)和菲关系型数据库
表就是关系
或者说是表与表之间存在关系
- 所有的关系型数据库都需要通过sql语言来操作
- 所有的关系型数据库在操作之前都需要设计表结构
- 而且数据表还支持约束
- 非关系型数据酷非常的灵活
- MonggoDb是长得最像关系型数据库的非关系型数据库
- 也就是说你可以任意的往里面存数据
MongoDB
下载与安装以及配置环境变量
在官网下载速度下载很慢可以复制下载链接到迅雷下载 ,安装一直next就行了
配置环境变量 将mongodb中的bin文件路径设置到环境变量的path里
通过cmd操作台 mongod -- version
查看是否安装完成
开启关闭MongoDB
关闭:
crlt +c
修改数据库路径
C:\Users\Mr.Deng>mongod --dbpath = “新的路径”
连接和退出数据库
连接数据库: 开启数据库后在新的cmd中输入 mongo// 会自动链接本机的数据库
断开数据库 : exit
基本操作
查看所有的数据库 show dbs
最开始有系统默认的数据库
查看当前所在的数据库 db
如果没有在某个数据库 会自动到test数据库 但是其实没有这个库
切换到指定的数据(如果没有则自动创建): use 数据库名称
虽然创建了数据库但是 总的数据库里还没有这个库
插入数据
当某个库中有了数据以后 数据库就能查找出来
查询students中的数据
对象数据自动添加了 id
可以自由的添加不同类型的对象 但是关系型数据库就不行
在node中操作mongoDB
方法一:使用官方文档操作
https://github.com/mongodb/node-mongodb-native
方法二:使用mongoose
网址:http://www.mongoosejs.net
下载: npm i mongoose
开启数据库 添加数据:在JavaScript中添加如下代码
这样就可以在JavaScript中添加
const mongoose = require('mongoose');
//连接数据库 这个数据库不用存在 插入数据后会自动生成
mongoose.connect('mongodb://localhost/test');
//创建一个模型
//就是在设计数据库
//MongoDB是动态的,非常灵活,只需要在代码中设计你的数据库就可以了 cat是个数组 存储了对象
const Cat = mongoose.model('Cat', { name: String });
//实例化一个Cat
const kitty = new Cat({ name: 'Zildjian' });
kitty.save().then(() => console.log('meow'));
当在test中添加了cats后就能在mongo数据库中找到了
mongoose默认连接在test中
mongoose开始
新增一个文档步骤:
const mongoose = require('mongoose');
var Schema = mongoose.Schema;
//1.第一步连接数据库
mongoose.connect('mongodb://localhost/test');
var Schema = mongoose.Schema;
//2.设计文档结构(表结构)结构
var userSchema = new Schema({
username: {
type: String,
required: true //必须有
},
password: {
type: String,
required: true
},
emai: {
type: String
}
})
//3.将一个文档结构发布为模型
//mongoose.model()就是用来发布架构发布为model
//第一个参数为大写名词单字符串用来表示数据库名称,mongoose会自动把大写字符串转化为小写复数的集合名称
// 如User 变为 users
//第二个参数 架构userSchema
var User = mongoose.model('User', userSchema);
//4.当我们有了构造函数之后就可以对users集合中的数据为所欲为了
var admin = new User({
username: 'admin',
password: '123456',
email: "2019214705@qq.com"
})
//将数据永久化
admin.save(function(err, ret) {
if (err) {
console.log('保存失败')
} else {
console.log('保存成功')
console.log(ret);
}
})
在node中执行这个js文件就可以了 node demo.js
注意数据库必须始终开着
结果:
添加数据
var admin = new User({
username: 'admin',
password: '123456',
email: "2019214705@qq.com"
})
var dz = new User({
username: 'dz',
password: '123444',
email: '123123@qq.com'
})
查询数据
查询所有数据: User.find(回调函数)
//查询所有数据
//再次证明了User集合中是一个数组
User.find(
function(err, ret) {
if (err) {
console.log('查询失败')
} else {
console.log(ret)
}
}
)
按条件查询所有数据:User.find(条件,回调函数)
按条件查询某个数据:User.findOne(条件,回调函数)
// 按条件查询
// User.find({ 查找的条件 }, 回调函数)
console.log('按条件查找数据:');
User.findOne({ username: 'dz' }, function(err, ret) {
if (err) {
console.log('按条件查询失败')
} else {
console.log(ret)
}
})
删除数据
删除所有:User.remove({条件},回调函数)
根据条件删除某一个:model.findOneAndRemove(conditions,[options],[callback])
根据ID删除某一个:model.findByIdAndRemove(conditions,[options],[callback])
User.remove({ username: 'admin' }, function(err, ret) {
if (err) {
console.log('删除失败')
}
})
User.find(
function(err, ret) {
if (err) {
console.log('查询失败')
} else {
console.log(ret)
}
}
)
修改数据
User.findByIdAndUpdate(‘id’,{修改的内容},回调函数);
User.findOneAndUpdate(conditions,[update],[options],callback)
//更新数据
User.findByIdAndUpdate('606d5d14b8ae6141345f5857', {
username: 'dzz',
password: '12323'
}, function(err, ret) {
if (err) {
console.log('修改失败')
} else {
console.log('修改成功')
}
})
mongoDB数据库概念
Promise
回调地狱
回调函数中嵌套回调函数
同一个作用域中的回调函数的执行顺序是随机的 无法保证执行顺序
//回调函数执行顺序是随机的
var fs = require('fs');
fs.readFile('./demo1.js', function(err, ret) {
if (err) {
console.log('aaa');
}
})
fs.readFile('./demo1.js', function(err, ret) {
if (err) {
console.log('bbb');
}
})
fs.readFile('./demo1.js', function(err, ret) {
if (err) {
console.log('ccc');
}
})
结果:每次执行的结果不一样,因为JavaScript是多线程的
解决方法:回调地狱 可以让异步函数有顺序的执行
回调地狱:异步函数嵌套异步函数
var fs = require('fs');
fs.readFile('./demo1.js', function(err, ret) {
if (err) {
console.log('aaa');
}
fs.readFile('./demo1.js', function(err, ret) {
if (err) {
console.log('bbb');
}
fs.readFile('./demo1.js', function(err, ret) {
if (err) {
console.log('ccc');
}
})
})
})
结果:每次都是按顺序执行
promise的作用:为了解决回调地狱编码方式带来的丑陋的问题,在ES6中新增了一个API名字叫做promise,是一个构造函数
promise有两种状态,默认状态是pending(正在做)
promise
使用方法
new promise()
promise本身不是异步的,只是一个容器,一旦创建就开始执行
.then()就是一个回调函数来得到promise中的异步函数的结果,根据不同状态代用不同回调函数
//promise函数
var fs = require('fs');
var p1 = new Promise(function(resolve, reject) {
fs.readFile('./demo1.js', function(err, ret) {
if (err) {
reject(err);
} else {
// 承诺容器成功了
// 将容器的pending状态改为Resolved状态
//也就是说这里调用的方法其实是resolve方法实际上是then方法传递的那个function,回调函数的到结果
resolve(ret)
}
})
})
// p1就是那个承诺结果
p1.then(
//当状态位resolved执行这个函数,function就是resolve(ret)
function(data) {
console.log(data);
},
//这个funtion就是reject(err)
function(err) {
console.log('读取文件失败了', err);
});
.then回调函数解决回调地狱问题
.then会接收前一个函数的返回值
var fs = require('fs');
var p1 = new Promise(function(resolve, reject) {
fs.readFile('./demo1.json', 'utf8', function(err, ret) {
if (err) {
reject(err);
} else {
// 承诺容器成功了
// 将容器的pending状态改为Resolved状态
//也就是说这里调用的方法其实是resolve方法实际上是then方法传递的那个function,回调函数的到结果
resolve(ret)
}
})
})
var p2 = new Promise(function(resolve, reject) {
fs.readFile('./demo2.json', 'utf8', function(err, ret) {
if (err) {
reject(err);
} else {
// 承诺容器成功了
// 将容器的pending状态改为Resolved状态
//也就是说这里调用的方法其实是resolve方法实际上是then方法传递的那个function,回调函数的到结果
resolve(ret)
}
})
})
var p3 = new Promise(function(resolve, reject) {
fs.readFile('./demo3.json', 'utf8', function(err, ret) {
if (err) {
reject(err);
} else {
// 承诺容器成功了
// 将容器的pending状态改为Resolved状态
//也就是说这里调用的方法其实是resolve方法实际上是then方法传递的那个function,回调函数的到结果
resolve(ret)
}
})
})
// p1就是那个承诺结果
p1.then(
//当状态位resolved执行这个函数,function就是resolve(ret)
function(data) {
console.log(data);
return p2;
},
//这个funtion就是reject(err)
function(err) {
console.log('读取文件失败了', err);
})
.then(function(data) {
console.log(data);
return p3;
})
.then(function(data) {
console.log(data);
})
分别声明几个promise容器,.then会接受上一个函数的resolved状态的函数的结果作为funtion函数,如果上一个resolved没有返回任何结果 funtion函数返回undefined
promise封装readFile函数
promise可以封装所有异步函数
//通过promise函数封装readFile函数
var fs = require('fs');
function PreadFile(filePath) {
return new Promise(function(resolve, reject) {
fs.readFile(filePath, 'utf8', function(err, ret) {
if (err) {
reject(err);
} else {
// 承诺容器成功了
// 将容器的pending状态改为Resolved状态
//也就是说这里调用的方法其实是resolve方法实际上是then方法传递的那个function,回调函数的到结果
resolve(ret)
}
})
})
}
PreadFile('./demo1.json')
.then(
function(data) {
console.log(data);
return PreadFile('./demo2.json')
})
.then(function(data) {
console.log(data);
return PreadFile('./demo3.json')
})
.then(
function(data) {
console.log(data);
})
promise的应用场景
通过两个接口获取两个数据的时候,必须用嵌套函数,这时候就可以用promise
如Ajax请求两个文件的数据时
用promise封装ajax
只有promise函数才可以.then所以必须返回promise函数
function Pget(url, callback) {
return new Promise(
function(resolve, reject) {
var Oreq = new XMLHttpRequest();
//当请求调用成功之后调用的函数
Oreq.onload = function() {
//callback&&callback()两个函数
callback && callback(JSON.parse(Oreq.responseText));
resolve(JSON.parse(Oreq.responseText));
}
Oreq.onerror = function(error) {
reject(error);
}
Oreq.open("get", url, true);
Oreq.send();
}
)
}
//既可以pget(url,回调函数) 也可以pget(url).then
// Pget('./json.json').then(function(data) {
// console.log(data);
// })
Pget('./json.json', function(data) {
console.log(data);
})
promise数据库操作例子
数据库的所有操作都是异步操作
实现功能:先查找后判断是否存在再创建数据
.then会接受前面一个函数返回的数据作为.then函数的参数或者函数
// 用户注册案例
//先判断用户是否存在
//如果不存在就创建并保存
//链式查找
User.findOne({
username: '666'
}).then(function(data) {
if (data) {
console.log('用户已存在');
} else {
return new User({
username: '666',
password: '3333',
// emai: '213123@qq.cm'
}).save();
}
}).then(function(User) {
})