Promise
promise 容器概念:
callback hell(回调地狱):
文件的读取无法判断执行顺序(文件的执行顺序是依据文件的大小来决定的)(异步api无法保证文件的执行顺序)
var fs = require('fs');
fs.readFile('./data/a.text','utf8',function(err,data){
if(err){
// 1 读取失败直接打印输出读取失败
return console.log('读取失败');
// 2 抛出异常
// 阻止程序的执行
// 把错误信息打印到控制台
throw err;
}
console.log(data);
});
fs.readFile('./data/b.text','utf8',function(err,data){
if(err){
// 1 读取失败直接打印输出读取失败
return console.log('读取失败');
// 2 抛出异常
// 阻止程序的执行
// 把错误信息打印到控制台
throw err;
}
console.log(data);
});
通过回调嵌套的方式来保证顺序:
var fs = require('fs');
fs.readFile('./data/a.text','utf8',function(err,data){
if(err){
// 1 读取失败直接打印输出读取失败
return console.log('读取失败');
// 2 抛出异常
// 阻止程序的执行
// 把错误信息打印到控制台
throw err;
}
console.log(data);
fs.readFile('./data/b.text','utf8',function(err,data){
if(err){
// 1 读取失败直接打印输出读取失败
return console.log('读取失败');
// 2 抛出异常
// 阻止程序的执行
// 把错误信息打印到控制台
throw err;
}
console.log(data);
fs.readFile('./data/a.text','utf8',function(err,data){
if(err){
// 1 读取失败直接打印输出读取失败
return console.log('读取失败');
// 2 抛出异常
// 阻止程序的执行
// 把错误信息打印到控制台
throw err;
}
console.log(data);
});
});
});
为了解决以上编码方式带来的问题(回调地狱嵌套),所以在EcmaScript6新增了一个API:Promise
。
- Promise:承诺,保证
- Promise本身不是异步的,但往往都是内部封装一个异步任务
基本语法:
var fs = require('fs')
// 在EcmaScript 6 中新增了一个API Promise
// Promise 是一个构造函数
// 创建 Promise 容器
// 1.给别人一个承诺 I promise you
// Promise 容器一旦创建,就开始执行里面的代码
var p1 = new Promise(function(resolve, reject) {
fs.readFile('./data/a.txt', 'utf-8', function(err, data) {
if (err) {
// 失败了,承诺容器中的任务失败了
// console.log(err)
// 把容器的Pending状态变为Rejected
// 调用的reject方法实际上就是then方法传递的第二个参数函数function
reject(err)
} else {
// 承诺容器中的任务成功了
// console.log(data)
// 把容器的Pending状态变为成功
// 也就是说这里调用的resolve方法实际上就是then方法传递的第一个function
resolve(data)
}
})
})
// p1 就是那个承诺
// 当 p1 成功了,然后(then)做指定的操作
// then 方法接收的function就是容器中的resolve函数
p1.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, 'utf-8', 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)
})
var fs = require('fs')
// 在EcmaScript 6 中新增了一个API Promise
// Promise 是一个构造函数
// 创建 Promise 容器
// 1.给别人一个承诺 I promise you
// Promise 容器一旦创建,就开始执行里面的代码
var p1 = new Promise(function(resolve, reject) {
fs.readFile('./data/a.txt', 'utf-8', function(err, data) {
if (err) {
// 失败了,承诺容器中的任务失败了
// console.log(err)
// 把容器的Pending状态变为Rejected
// 调用的reject方法实际上就是then方法传递的第二个参数函数function
reject(err)
} else {
// 承诺容器中的任务成功了
// console.log(data)
// 把容器的Pending状态变为成功
// 也就是说这里调用的resolve方法实际上就是then方法传递的第一个function
resolve(data)
}
})
})
var p2 = new Promise(function(resolve, reject) {
fs.readFile('./data/b.txt', 'utf-8', function(err, data) {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
var p3 = new Promise(function(resolve, reject) {
fs.readFile('./data/c.txt', 'utf-8', 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 一个 promise 对象的时候,后续的then中的方法的第一个参数会作为p2 的resolve
return p2
}, function(err) {
console.log('读取文件失败', err)
}).then(function(data) {
console.log(data)
return p3
}).then(function(data) {
console.log(data)
})
需求:分别向两个接口:users和jobs发送请求,获取响应数据,将数据通过art-template 模板渲染到html页面上
第一种:使用自己封装的callback方式
data.json:
{
"users": [{
"id": 1,
"username": "admin",
"age": 22,
"job": 4
},
{
"id": 2,
"username": "admin2",
"age": 18,
"job": 1
},
{
"id": 3,
"username": "admin3",
"age": 18,
"job": 1
}
],
"jobs": [{
"id": 1,
"name": "学生"
},
{
"id": 2,
"name": "老师"
},
{
"id": 3,
"name": "司机"
},
{
"id": 4,
"name": "演员"
},
{
"id": 5,
"name": "画家"
},
{
"id": 6,
"name": "电竞人"
}
]
}
这里使用json-server来开启一个服务:
首先,安装 json-server: npm install -g json-server
然后通过命令:json-server --watch data.json
启动服务:
由于用到了模板引擎来将数据渲染到页面上,所以需要再安装一个art-template包:
npm i art-template
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<form action="#" id="user_form">
</form>
<script type="text/text/template" id="tpl">
<label for="">用户名</label>
<input type="text" value="{
{ user.username }}">
<label for="">年龄</label>
<input type="text" value="{
{ user.age }}">
<label for="">职业</label>
<select name="" id="">
{
{
each jobs }}
{
{
if user.job === $value.id }}
<option value="{
{ $value.id }}" selected="selected">{
{
$value.name }}</option>
{
{
else }}
<option value="{
{ $value.id }}">{
{
$value.name }}</option>
{
{
/if }}
{
{
/each }}
</select>
</script>
<script src="node_modules/art-template/lib/template-web.js"></script>
<script>
// 用户表
// 其中一个接口获取用户数据
// 职业:1
// 职业信息表
// 其中一个接口获取所有的职业信息
get('http://127.0.0.1:3000/users/1', function(userData) {
// data = JSON.parse(data)
get('http://127.0.0.1:3000/jobs', function(jobsData) {
// console.log(userData, jobsData)
var htmlStr = template('tpl', {
user: JSON.parse(userData),
jobs: JSON.parse(jobsData)
})
console.log(htmlStr)
document.querySelector('#user_form').innerHTML = htmlStr
})
})
function get(url, callback) {
var oReq = new XMLHttpRequest()
// 当请求加载成功之后要调用指定的函数
oReq.onload = function() {
// 我现在需要得到这里的 oReq.responseText
callback(oReq.responseText)
}
oReq.open("get", url, true)
oReq.send()
}
</script>
</body>
</html>
第二种:使用jquery的promise方式
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<form action="#" id="user_form">
</form>
<script type="text/text/template" id="tpl">
<label for="">用户名</label>
<input type="text" value="{
{ user.username }}">
<label for="">年龄</label>
<input type="text" value="{
{ user.age }}">
<label for="">职业</label>
<select name="" id="">
{
{
each jobs }}
{
{
if user.job === $value.id }}
<option value="{
{ $value.id }}" selected="selected">{
{
$value.name }}</option>
{
{
else }}
<option value="{
{ $value.id }}">{
{
$value.name }}</option>
{
{
/if }}
{
{
/each }}
</select>
</script>
<script src="node_modules/jquery/dist/jquery.js"></script>
<script src="node_modules/art-template/lib/template-web.js"></script>
<script>
// 用户表
// 其中一个接口获取用户数据
// 职业:1
// 职业信息表
// 其中一个接口获取所有的职业信息
/* get('http://127.0.0.1:3000/users/1', function(userData) {
// data = JSON.parse(data)
get('http://127.0.0.1:3000/jobs', function(jobsData) {
// console.log(userData, jobsData)
var htmlStr = template('tpl', {
user: JSON.parse(userData),
jobs: JSON.parse(jobsData)
})
console.log(htmlStr)
document.querySelector('#user_form').innerHTML = htmlStr
})
}) */
var data = {
}
$.get('http://127.0.0.1:3000/users/1')
.then(function(userData) {
console.log(userData)
data.user = userData
return $.get('http://127.0.0.1:3000/jobs')
})
.then(function(jobsData) {
console.log(jobsData)
data.jobs = jobsData
console.log(data)
var htmlStr = template('tpl', data)
console.log(htmlStr)
document.querySelector('#user_form').innerHTML = htmlStr
})
function get(url, callback) {
var oReq = new XMLHttpRequest()
// 当请求加载成功之后要调用指定的函数
oReq.onload = function() {
// 我现在需要得到这里的 oReq.responseText
callback(oReq.responseText)
}
oReq.open("get", url, true)
oReq.send()
}
</script>
</body>
</html>
3.用promise封装ajax版:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<form action="#" id="user_form">
</form>
<script type="text/text/template" id="tpl">
<label for="">用户名</label>
<input type="text" value="{
{ user.username }}">
<label for="">年龄</label>
<input type="text" value="{
{ user.age }}">
<label for="">职业</label>
<select name="" id="">
{
{
each jobs }}
{
{
if user.job === $value.id }}
<option value="{
{ $value.id }}" selected="selected">{
{
$value.name }}</option>
{
{
else }}
<option value="{
{ $value.id }}">{
{
$value.name }}</option>
{
{
/if }}
{
{
/each }}
</select>
</script>
<script src="node_modules/jquery/dist/jquery.js"></script>
<script src="node_modules/art-template/lib/template-web.js"></script>
<script>
// 用户表
// 其中一个接口获取用户数据
// 职业:1
// 职业信息表
// 其中一个接口获取所有的职业信息
/* get('http://127.0.0.1:3000/users/1', function(userData) {
// data = JSON.parse(data)
get('http://127.0.0.1:3000/jobs', function(jobsData) {
// console.log(userData, jobsData)
var htmlStr = template('tpl', {
user: JSON.parse(userData),
jobs: JSON.parse(jobsData)
})
console.log(htmlStr)
document.querySelector('#user_form').innerHTML = htmlStr
})
}) */
/*
var data = {}
$.get('http://127.0.0.1:3000/users/1')
.then(function(userData) {
console.log(userData)
data.user = userData
return $.get('http://127.0.0.1:3000/jobs')
})
.then(function(jobsData) {
console.log(jobsData)
data.jobs = jobsData
console.log(data)
var htmlStr = template('tpl', data)
console.log(htmlStr)
document.querySelector('#user_form').innerHTML = htmlStr
}) */
var data = {
}
get('http://127.0.0.1:3000/users/1')
.then(function(userData) {
data.user = userData
return $.get('http://127.0.0.1:3000/jobs')
})
.then(function(jobsData) {
data.jobs = jobsData
var htmlStr = template('tpl', data)
document.querySelector('#user_form').innerHTML = htmlStr
})
function get(url) {
return new Promise(function(resolve, reject) {
var oReq = new XMLHttpRequest()
// 当请求加载成功之后要调用指定的函数
oReq.onload = function() {
// 我现在需要得到这里的 oReq.responseText
resolve(JSON.parse(oReq.responseText))
}
oReq.onerror = function (err) {
reject(err)
}
oReq.open("get", url, true)
oReq.send()
})
}
/* function get(url, callback) {
var oReq = new XMLHttpRequest()
// 当请求加载成功之后要调用指定的函数
oReq.onload = function() {
// 我现在需要得到这里的 oReq.responseText
callback(oReq.responseText)
}
oReq.open("get", url, true)
oReq.send()
} */
</script>
</body>
</html>
mongoose所有的API都支持Promise:
// 查询所有
User.find()
.then(function(data){
console.log(data)
})
注册:
User.findOne({
username:'admin'},function(user){
if(user){
console.log('用户已存在')
} else {
new User({
username:'aaa',
password:'123',
email:'fffff'
}).save(function(){
console.log('注册成功');
})
}
})
User.findOne({
username:'admin'
})
.then(function(user){
if(user){
// 用户已经存在不能注册
console.log('用户已存在');
}
else{
// 用户不存在可以注册
return new User({
username:'aaa',
password:'123',
email:'fffff'
}).save();
}
})
.then(funciton(ret){
console.log('注册成功');
})
Generator
async函数