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方法传递的第二个参数函数functionreject(err)} else {// 承诺容器中的任务成功了// console.log(data)// 把容器的Pending状态变为成功// 也就是说这里调用的resolve方法实际上就是then方法传递的第一个functionresolve(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方法传递的第二个参数函数functionreject(err)} else {// 承诺容器中的任务成功了// console.log(data)// 把容器的Pending状态变为成功// 也就是说这里调用的resolve方法实际上就是then方法传递的第一个functionresolve(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 的resolvereturn 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.responseTextcallback(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 = userDatareturn $.get('http://127.0.0.1:3000/jobs')}).then(function(jobsData) {console.log(jobsData)data.jobs = jobsDataconsole.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.responseTextcallback(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 = userDatareturn $.get('http://127.0.0.1:3000/jobs')}).then(function(jobsData) {console.log(jobsData)data.jobs = jobsDataconsole.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 = userDatareturn $.get('http://127.0.0.1:3000/jobs')}).then(function(jobsData) {data.jobs = jobsDatavar 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.responseTextresolve(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.responseTextcallback(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函数