1. 概述
在JavaScript的世界中,所有代码都是单线程执行的,在浏览器中,网络请求需要异步请求,出现了ajax技术,Promise辅助我们做异步操作,所谓promis就是“承诺未来会执行”,其实我们更多是用做“先写好任务,再某个时机获取执行结果”
2. 入门
2.1 创建Promise
<script>
let promise = new Promise(function() {
console.log('进入了Promise');
});
console.log('end');
</script>
执行结果
我们发现只要创建了promise,会==立即执行它内部的回调函数==
进入了Promise
end
2.2 解决Promise创建即执行问题
promise回调函数要做的事情,很多时候并不是要立刻执行,比如我们封装了一个网络请求,我们要点击的时候才发出去,这就是个问题了,如果解决?
答:使用函数返回值来解决这个问题!!!
<script>
let fn = function() {
return new Promise(function() {
console.log('进入了Promise');
});
}
console.log('end');
fn();
</script>
执行结果
执行了fn函数,相当于把Promise创建return出来,而创建的同时,相当于执行了Promise内部的回调函数
end
进入了Promise
2.3 模拟用Promise封装网络请求
- Promise构造函数可以接受一个回调函数,回调函数可以接受2个参数
第一个代表:成功的回调函数resolve;第二个代表:失败的回调函数reject
- Promise实例对象获执行结果,可以通过2个方法
then方法:接收resolve函数执行结果;catch:接收reject函数执行结果
<script type="text/javascript">
// 1. 模拟把要做的事情先封装起来
var promise = new Promise(function(resolve, reject){
console.log('执行promise');
// 模拟请求回调
let flag = parseInt(Math.random()*2) == 1;
if (flag) {
setTimeout(resolve, 2000, '请求成功');
}else {
setTimeout(reject, 2000, '请求失败');
}
});
// 2. 模拟执行网络请求,拿到请求结果
promise.then(function(res){
// 成功被这个函数接收
console.log(res);
}).catch(function(res){
// 失败被这个函数接收
console.log(res);
});
console.log('结束');
</script>
执行结果
未将Promise用函数包起来,HTML一加载到这里就会立即执行网络请求,而不是适当时机,还要优化
执行promise
结束
请求成功
2.4 使用Promise完善网络请求封装
准备一个Java测试接口
@WebServlet("/test")
public class TestServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ResultInfo resultInfo = new ResultInfo();
// 随机成功或失败
if (ThreadLocalRandom.current().nextBoolean()) {
resultInfo.setFlag(true);
resultInfo.setErrorMsg("请求成功");
}else {
resultInfo.setFlag(false);
resultInfo.setErrorMsg("请求失败");
}
response.setContentType("application/json;charset=utf-8");
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.writeValue(response.getWriter(), resultInfo);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
前端代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<button type="button" id="btn">发起请求</button>
<div id="info">请求结果:</div>
</body>
</html>
<script>
// 1. ajax函数将返回Promise对象:
let ajax = function (method, url, data) {
var request = new XMLHttpRequest();
return new Promise(function (resolve, reject) {
request.onreadystatechange = function () {
if (request.readyState === 4) {
if (request.status === 200) {
let res = JSON.parse(request.response);
if (res['flag']) {
// 请求成功
resolve(request.responseText);
}else {
// 接口反馈请起有问题
reject(request.responseText);
}
} else {
// 网络问题
reject(request.status);
}
}
};
request.open(method, url);
request.send(data);
});
}
// 2. 点击按钮发起请求
document.getElementById("btn").onclick = function() {
ajax('POST', 'http://192.168.142.129/travel/test', {'key': 'is a request param'})
.then(function(res) {
console.log('请求成功数据:' + res);
}).catch(function(res) {
console.log('请求失败数据:' + res);
});
}
</script>
3. 其他用法
3.1 合并任务All
有时候可能某个任务,需要前几个任务完成后,才能执行这个任务
比如:多线程请求各自下载一个大图片某一部分,最终确保都执行完毕后,再执行合并图片的任务,这个任务执行时机取决于最后一个完成任务的线程
<script>
let promise1 = new Promise(function(resolve, reject){
setTimeout(resolve('promise1执行完毕'), 1000);
});
let promise2 = new Promise(function(resolve, reject){
// 定时器另外写法,传参写后面
setTimeout(resolve, 5000, 'promise2执行完毕');
});
// 合并执行
Promise.all([promise1, promise2]).then(function(results){
console.log(results);
});
</script>
执行结果
5秒钟后执行回调,回调函数结果是多个promis传入的结果合并成数组
['promise1执行完毕', 'promise2执行完毕']
3.2 竞赛任务Race
有时候可能多个类似任务执行,只要有一个先执行完就可以
比如:只录取第一名,大家都做一样的事情,但是谁先赢了,其他人也不用比了
<script>
let promise1 = function(){
return new Promise(function(resolve, reject){
// 定时器另外写法,传参写后面
setTimeout(resolve, 5000, 'promise1执行完毕');
})
};
let promise2 = function(){
return new Promise(function(resolve, reject){
// 定时器另外写法,传参写后面
setTimeout(resolve, 3000, 'promise2执行完毕');
})
};
// 合并执行
Promise.race([promise1(), promise2()]).then(function(result){
console.log(result);
});
</script>
执行结果
直接执行了promise2,其实promise1也是继续执行,只是结果被丢弃了
promise2执行完毕