在前端編程中,處理一些簡短、快速的操作,在主線程中就可以完成。 但是,在處理一些耗時比較長以至於比較明顯的事情,比如讀取一個大文件或者發出一個網路請求,就需要非同步編程來實現,以避免只用主線程時造成頁面一時無法響應的事情。 以發送網路請求為例,在以往的JavaScript中,使用多個回調函數來處理請求 ...
在前端編程中,處理一些簡短、快速的操作,在主線程中就可以完成。
但是,在處理一些耗時比較長以至於比較明顯的事情,比如讀取一個大文件或者發出一個網路請求,就需要非同步編程來實現,以避免只用主線程時造成頁面一時無法響應的事情。
以發送網路請求為例,在以往的JavaScript中,使用多個回調函數來處理請求返回的多個狀態,如下麵的代碼:
var xhr = new XMLHttpRequest();
xhr.onload = function () { // 請求成功時調用
document.getElementById("box1").innerHTML=xhr.responseText;
}
xhr.onerror = function () { // 請求失敗時調用
document.getElementById("box1").innerHTML="請求出錯";
}
xhr.open("GET", "./book1/chapt1.php", true);
xhr.send();
如果該請求因為網路延遲等原因沒有回應,頁面就會卡在該位置而不會執行下麵的代碼,造成頁面展示不佳的問題。
而使用 Promise 對象就不會有這個問題。如下麵的代碼:
function ajax(URL) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
req.onload = function () {
if (req.status === 200) {
resolve(req.responseText);
} else {
reject(new Error(req.statusText));
}
};
req.onerror = function () {
reject(new Error(req.statusText));
};
req.open('GET', URL, true);
req.send();
});
}
var URL = "./book1/chapt1.php";
<!--
ajax函數返回的Promise對象函數會在子線程中執行
主線程可以執行接下去的代碼
Promise的then函數和catch函數會等待請求的返回結果
-->
ajax(URL).then((value) => {
document.getElementById("box1") = value; // 請求成功
}).catch((error) => {
document.getElementById("box1") = error; // 請求失敗
});
這樣看,Promise雖然解決了問題,但看起來更加複雜了,代碼也更多了,但是在接下來的例子中,你會看到Promise使代碼更優雅的應用。
例如有這樣一個“函數瀑布”實現的功能:
setTimeout(function () {
console.log("First");
setTimeout(function () {
console.log("Second");
setTimeout(function () {
console.log("Third");
setTimeout(function () {
console.log("Fourth");
}, 2000);
}, 1000);
}, 2000);
}, 1000);
可以想象,在一個複雜的程式中,這樣的函數無論是維護還是異常處理都是一件特別繁瑣的事情,而且會讓縮進格式變得非常冗贅。
現在使用Promise來實現就有條理和優雅的多:
function print(delay, message) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log(message);
resolve();
}, delay);
});
}
print(1000, "First").then(function () {
return print(2000, "Second");
}).then(function () {
return print(1000, "Third");
}).then(function () {
print(2000, "fourd");
});