Promise使用

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)絡請求

  1. Promise構造函數(shù)可以接受一個回調函數(shù),回調函數(shù)可以接受2個參數(shù)

第一個代表:成功的回調函數(shù)resolve;第二個代表:失敗的回調函數(shù)reject

  1. 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í)行完畢

4. 參考資料

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容