1. 概述
在JavaScript的世界中,所有代碼都是單線程執(zhí)行的,在瀏覽器中,網(wǎng)絡請求需要異步請求,出現(xiàn)了ajax技術,Promise輔助我們做異步操作,所謂promis就是“承諾未來會執(zhí)行”,其實我們更多是用做“先寫好任務,再某個時機獲取執(zhí)行結果”
2. 入門
2.1 創(chuàng)建Promise
<script>
let promise = new Promise(function() {
console.log('進入了Promise');
});
console.log('end');
</script>
執(zhí)行結果
我們發(fā)現(xiàn)只要創(chuàng)建了promise,會==立即執(zhí)行它內部的回調函數(shù)==
進入了Promise
end
2.2 解決Promise創(chuàng)建即執(zhí)行問題
promise回調函數(shù)要做的事情,很多時候并不是要立刻執(zhí)行,比如我們封裝了一個網(wǎng)絡請求,我們要點擊的時候才發(fā)出去,這就是個問題了,如果解決?
答:使用函數(shù)返回值來解決這個問題?。。?/p>
<script>
let fn = function() {
return new Promise(function() {
console.log('進入了Promise');
});
}
console.log('end');
fn();
</script>
執(zhí)行結果
執(zhí)行了fn函數(shù),相當于把Promise創(chuàng)建return出來,而創(chuàng)建的同時,相當于執(zhí)行了Promise內部的回調函數(shù)
end
進入了Promise
2.3 模擬用Promise封裝網(wǎng)絡請求
- Promise構造函數(shù)可以接受一個回調函數(shù),回調函數(shù)可以接受2個參數(shù)
第一個代表:成功的回調函數(shù)resolve;第二個代表:失敗的回調函數(shù)reject
- Promise實例對象獲執(zhí)行結果,可以通過2個方法
then方法:接收resolve函數(shù)執(zhí)行結果;catch:接收reject函數(shù)執(zhí)行結果
<script type="text/javascript">
// 1. 模擬把要做的事情先封裝起來
var promise = new Promise(function(resolve, reject){
console.log('執(zhí)行promise');
// 模擬請求回調
let flag = parseInt(Math.random()*2) == 1;
if (flag) {
setTimeout(resolve, 2000, '請求成功');
}else {
setTimeout(reject, 2000, '請求失敗');
}
});
// 2. 模擬執(zhí)行網(wǎng)絡請求,拿到請求結果
promise.then(function(res){
// 成功被這個函數(shù)接收
console.log(res);
}).catch(function(res){
// 失敗被這個函數(shù)接收
console.log(res);
});
console.log('結束');
</script>
執(zhí)行結果
未將Promise用函數(shù)包起來,HTML一加載到這里就會立即執(zhí)行網(wǎng)絡請求,而不是適當時機,還要優(yōu)化
執(zhí)行promise
結束
請求成功
2.4 使用Promise完善網(wǎng)絡請求封裝
準備一個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">發(fā)起請求</button>
<div id="info">請求結果:</div>
</body>
</html>
<script>
// 1. ajax函數(shù)將返回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 {
// 網(wǎng)絡問題
reject(request.status);
}
}
};
request.open(method, url);
request.send(data);
});
}
// 2. 點擊按鈕發(fā)起請求
document.getElementById("btn").onclick = function() {
ajax('POST', 'http://192.168.142.129/travel/test', {'key': 'is a request param'})
.then(function(res) {
console.log('請求成功數(shù)據(jù):' + res);
}).catch(function(res) {
console.log('請求失敗數(shù)據(jù):' + res);
});
}
</script>
3. 其他用法
3.1 合并任務All
有時候可能某個任務,需要前幾個任務完成后,才能執(zhí)行這個任務
比如:多線程請求各自下載一個大圖片某一部分,最終確保都執(zhí)行完畢后,再執(zhí)行合并圖片的任務,這個任務執(zhí)行時機取決于最后一個完成任務的線程
<script>
let promise1 = new Promise(function(resolve, reject){
setTimeout(resolve('promise1執(zhí)行完畢'), 1000);
});
let promise2 = new Promise(function(resolve, reject){
// 定時器另外寫法,傳參寫后面
setTimeout(resolve, 5000, 'promise2執(zhí)行完畢');
});
// 合并執(zhí)行
Promise.all([promise1, promise2]).then(function(results){
console.log(results);
});
</script>
執(zhí)行結果
5秒鐘后執(zhí)行回調,回調函數(shù)結果是多個promis傳入的結果合并成數(shù)組
['promise1執(zhí)行完畢', 'promise2執(zhí)行完畢']
3.2 競賽任務Race
有時候可能多個類似任務執(zhí)行,只要有一個先執(zhí)行完就可以
比如:只錄取第一名,大家都做一樣的事情,但是誰先贏了,其他人也不用比了
<script>
let promise1 = function(){
return new Promise(function(resolve, reject){
// 定時器另外寫法,傳參寫后面
setTimeout(resolve, 5000, 'promise1執(zhí)行完畢');
})
};
let promise2 = function(){
return new Promise(function(resolve, reject){
// 定時器另外寫法,傳參寫后面
setTimeout(resolve, 3000, 'promise2執(zhí)行完畢');
})
};
// 合并執(zhí)行
Promise.race([promise1(), promise2()]).then(function(result){
console.log(result);
});
</script>
執(zhí)行結果
直接執(zhí)行了promise2,其實promise1也是繼續(xù)執(zhí)行,只是結果被丟棄了
promise2執(zhí)行完畢