Promise的介紹和優點

es6中的promise時異步編程的一種方案. 從語法上來講, promise是一個對象, 它可以獲取異步操作的消息

promise對象, 可以將異步操作以同步的流程表達出來

好處:

可以很好的解決回調地獄問題 (避免了層層嵌套的回調函數)

語法非常簡潔. promise對象提供簡介的api, 使得控制異步操作更加容易

Promise的基本用法

1 new實例化一個promise對象, promise的構造函數中傳遞一個參數, 是一個函數, 該函數用於處理異步任務

2 傳入兩個參數: resolve和reject, 分別代表異步執行成功後的回調函數和失敗後的回調函數

3 通過promise.then()處理返回結構

實例

// 第一步:model層的接口封裝
const promise = new Promise((resolve, reject) => {
    // 這裏做異步任務(比如ajax 請求接口。這裏暫時用定時器代替)
    setTimeout(function() {
        var data = { retCode: 0, msg: 'qianguyihao' }; // 接口返回的數據
        if (data.retCode == 0) {
            // 接口請求成功時調用
            resolve(data);
        } else {
            // 接口請求失敗時調用
            reject({ retCode: -1, msg: 'network error' });
        }
    }, 100);
});

// 第二步:業務層的接口調用。這裏的 data 就是 從 resolve 和 reject 傳過來的,也就是從接口拿到的數據
promise.then(data => {
    // 從 resolve 獲取正常結果
    console.log(data);
}).catch(data => {
    // 從 reject 獲取異常結果
    console.log(data);
});

Promise對象的3個狀態

初始化狀態(等待狀態): pending

成功狀態: fullfilled

失敗狀態: rejected

(1)當new Promise()執行之後,promise對象的狀態會被初始化為pending,這個狀態是初始化狀態。new Promise()這行代碼,括號裏的內容是同步執行的。括號裏定義一個function,function有兩個參數:resolve和reject。如下:

  • 如果請求成功了,則執行resolve(),此時,promise的狀態會被自動修改為fullfilled。
  • 如果請求失敗了,則執行reject(),此時,promise的狀態會被自動修改為rejected

(2)promise.then()方法,括號裏面有兩個參數,分別代表兩個函數 function1 和 function2:

  • 如果promise的狀態為fullfilled(意思是:如果請求成功),則執行function1裏的內容
  • 如果promise的狀態為rejected(意思是,如果請求失敗),則執行function2裏的內容

Promise處理多次ajax請求(鏈式調用)

promise可以把原本的多層嵌套調用改為鏈式調用

/*
	基於Promise發送Ajax請求
*/
function queryData(url) {
    var promise = new Promise((resolve, reject) => {
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function() {
            if (xhr.readyState != 4) return;
            if (xhr.readyState == 4 && xhr.status == 200) {
                // 處理正常情況
                resolve(xhr.responseText); // xhr.responseText 是從接口拿到的數據
            } else {
                // 處理異常情況
                reject('接口請求失敗');
            }
        };
        xhr.responseType = 'json'; // 設置返回的數據類型
        xhr.open('get', url);
        xhr.send(null); // 請求接口
    });
    return promise;
}
// 發送多個ajax請求並且保證順序
queryData('http://localhost:3000/api1')
    .then(
        data1 => {
            console.log(JSON.stringify(data1));
            // 請求完接口1後,繼續請求接口2
            return queryData('http://localhost:3000/api2');
        },
        error1 => {
        	console.log(error1);
        }
    )
    .then(
        data2 => {
            console.log(JSON.stringify(data2));
            // 請求完接口2後,繼續請求接口3
            return queryData('http://localhost:3000/api3');
        },
        error2 => {
        	console.log(error2);
        }
    )
    .then(
        data3 => {
            // 獲取接口3返回的數據
            console.log(JSON.stringify(data3));
        },
        error3 => {
        	console.log(error3);
        }
	);

Promise的常用API: 實例方法

promise.then(): 獲取異步任務的正常結果

promise.catch(): 獲取異步任務的異步結果

promise.finaly(): 異步任務無論成功與否, 都會執行

queryData()
    .then(data => {
        // 從 resolve 獲取正常結果
        console.log('接口請求成功時,走這裏');
        console.log(data);
    })
    .catch(data => {
        // 從 reject 獲取異常結果
        console.log('接口請求失敗時,走這裏');
        console.log(data);
    })
    .finally(() => {
    	console.log('無論接口請求成功與否,都會走這裏');
    });
queryData()
    .then(
        data => {
            // 從 resolve 獲取正常結果
            console.log('接口請求成功時,走這裏');
            console.log(data);
        },
        data => {
            // 從 reject 獲取異常結果
            console.log('接口請求失敗時,走這裏');
            console.log(data);
        }
    )
    .finally(() => {
    	console.log('無論接口請求成功與否,都會走這裏');
});

Promise的常用API: 對象方法

promise.all(): 併發處理多個異步任務, 所有任務都執行成功, 才能得到結果.

promise.race(): 併發處理多個異步處理, 只要一個任務執行成功, 就能得到結果

/*
封裝 Promise 接口調用
*/
function queryData(url) {
    return new Promise((resolve, reject) => {
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function() {
            if (xhr.readyState != 4) return;
            if (xhr.readyState == 4 && xhr.status == 200) {
                // 處理正常結果
                resolve(xhr.responseText);
            } else {
                // 處理異常結果
                reject('服務器錯誤');
            }
        };
        xhr.open('get', url);
        xhr.send(null);
    });
}

var promise1 = queryData('http://localhost:3000/a1');
var promise2 = queryData('http://localhost:3000/a2');
var promise3 = queryData('http://localhost:3000/a3');

Promise.all([promise1, promise2, promise3]).then(result => {
	console.log(result);
});
/*
封裝 Promise 接口調用
*/
function queryData(url) {
    return new Promise((resolve, reject) => {
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function() {
            if (xhr.readyState != 4) return;
            if (xhr.readyState == 4 && xhr.status == 200) {
                // 處理正常結果
                resolve(xhr.responseText);
            } else {
                // 處理異常結果
                reject('服務器錯誤');
            }
        };
        xhr.open('get', url);
        xhr.send(null);
    });
}

var promise1 = queryData('http://localhost:3000/a1');
var promise2 = queryData('http://localhost:3000/a2');
var promise3 = queryData('http://localhost:3000/a3');

Promise.race([promise1, promise2, promise3]).then(result => {
	console.log(result);
});