JavaScript異步編程2——結合XMLHttpRequest使用Promise


1. 概述

在上一篇文章《JavaScript異步編程1——Promise的初步使用》,簡單介紹了一下Promise的初步使用。復習一下,Promise異步編程可以用如下的范式來編寫:

  1. 定義一個函數(function A),這個函數返回一個Promise對象。
  2. Promise對象的參數也是一個function B,內部進行了一個異步操作(通常是JavaScript提供的API)。
  3. function B對象的參數是兩個回調函數resolve和reject。如果函數內部進行的異步操作成功,回調resolve;否則回調reject。
  4. 調用function A,返回一個Promise對象,這樣異步操作就啟動了。
  5. 調用Promise對象的then方法,參數是resolve和reject的真正響應函數。當異步操作完成了,就會執行相應分支的響應函數。

采用以上范式,可以通過Promise來進行Ajax操作,也就是XMLHttpRequest,畢竟這個操作在Web應用中實在太常見了。

2. 詳論

首先仍然是准備一個HTML頁面:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <script src="./3rdParty/jquery-3.5.1.js"></script>
    <title>樣例</title>
</head>

<body>
    <div id = "container"> </div>
    <script src="./PromiseTest.js"></script>
</body>

</html>

如果不使用Promise,那么相應的JavaScript代碼為:

$(function () {

    var url = "./1.json";

    var req = new XMLHttpRequest();
    req.open('GET', url);

    req.onload = function () {        
        if (req.status == 200) {
            console.log(req.response);
        } else {           
            throw new Error(req.statusText);
        }
    };

    req.onerror = function () {
        throw new Error("Network Error");
    };

    req.send();
});

可以看到這里仍然是通過事件機制來實現異步行為。接下來采用前面提到的編程范式將其改造成Promise機制:

function get(url) {       
    return new Promise(function (resolve, reject) {      
        var req = new XMLHttpRequest();
        req.open('GET', url);

        req.onload = function () {
            //即使是404也會進入這個相應函數,所以需要檢測狀態
            if (req.status == 200) {
                //完成許諾,返回響應文本
                resolve(req.response);
            } else {
                //完成未完成,返回錯誤
                reject(Error(req.statusText));
            }
        };

        // 發生錯誤時的相應函數
        req.onerror = function () {
            reject(Error("Network Error"));
        };

        // 發送請求
        req.send();
    });
}

var addressUri = "./1.json";
get(addressUri).then(function (response) {
    console.log("Success!", response);      
}, function (error) {
    console.error("Failed!", error);
}); 

改造成Promise的過程與上一章並沒有什么不同,只不過函數內部調用XMLHttpRequest的流程更加復雜些。這兩個例子都是將事件改造成Promise,那不是意味着對於異步編程而言,Promise要優於事件呢?

不能完全這么肯定,但是可以確定的是事件並不總是異步編程的最優實踐。一個很顯然的問題就是:事件很適合處理在同一對象上多次發生的事情,但是事件偵聽器的響應函數可能並不是我們想要的——更多情況下,我們只想要直到兩個狀態,當異步操作完成的時候該做什么,當異步操作失敗的時候又該做什么,而這正是Promise擅長處理的。

例如這里的XMLHttpRequest操作,事件響應函數onload中的所有行為,並不都是異步請求成功時需要完成的,只有檢測訪問請求狀態為200時候,才需要進行請求成功時的回調函數。使用Promise,可以更准確的進行異步行為。

3. 參考

  1. Ajax原理-原生js的XMLHttpRequest對象意義
  2. Javascript異步編程的4種方法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM