學習 ECMAScript/JavaScript 6 - Promise 實際範例
我從過去用到 Promise 的 Web 前端開發案中,挑出兩個具有泛用性的應用函數,作為實際範例。若是不了解 Promise 基礎觀念,請先看「ECMAScript/JavaScript 6 - Promise 學習六步 」。
Promise 的應用函數:
- JSONRequest
- Until
JSONRequest
用 Promise 包裝的 XMLHttpRequest 函數。功能明確,呼叫 RESTful API 取回 JSON 資料。
下列為函數內容。也保存在我的 github: ajax.js。
/**
使用 Promise 實作,Promise 是 ECMAScript 6 規範項目。
因此需要支持 ECMAScript 6 標準的瀏覽器, IE 所有版本都不可用。
*/
function JSONRequest(http_method, url, body)
{
let promise = new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.addEventListener('load', () => {
// console.log('response loaded', xhr);
if (Number(xhr.status) >= 400) {
reject(xhr);
}
else if (xhr.responseText.length < 1) {
// console.log('only status code');
resolve();
}
else {
let result = null;
try {
result = JSON.parse(xhr.responseText);
}
catch (e) {
reject(xhr);
}
resolve(result);
}
});
xhr.addEventListener('error', () => {
console.log("request failed");
reject(xhr);
});
xhr.open(http_method, url);
xhr.setRequestHeader('Accept', 'application/json');
xhr.setRequestHeader('Content-Type', 'application/json');
if (body && typeof(body) == 'object') {
body = JSON.stringify(body);
}
xhr.send(body);
});
return promise;
}
使用情境如專案中使用 jQuery slim (不含 ajax 模組) 之時, JSONRequest 就是 jQuery.ajax 的替代品。
用法如下:
JSONRequest('GET', url)
.then(result => {
console.log('get response ', result);
})
let data = {
"name": "rock",
"level": 123
};
JSONRequest('POST', url, data)
.then(result => {
// result 已經分析成 JavaScript object
console.log('post response ', result);
})
Until
用 Promise 包裝的 setInterval 函數。
下列為函數內容。也保存在我的 github: until.js。
引數 expr 是一個函數,它應包含設計者指示的條件判斷內容,並回傳 true 或 false 。 Until() 會以 0.1 秒的頻率呼叫 expr 。當 expr 條件成立時,才執行 then 的內容。
引數 timeout 指定 Until 的最長工作秒數。若 expr 在超過 timeout 秒數後仍然為 false ,則執行 catch 的內容。 timeout 可省略,表示不限時。
function Until(expr, timeout)
{
let _timeout = timeout ? timeout * 10 : undefined;
let promise = new Promise((resolve, reject) => {
let count = 0;
let it = setInterval(() => {
if (expr()) {
clearInterval(it);
resolve(count/10); // elapsed seconds
return;
}
++count;
if (_timeout && count > _timeout) { // wait n seconds
clearInterval(it);
reject();
return;
}
}, 100) // 0.1 second interval.
});
return promise;
}
使用情境,主要用在限時操作的場合。當然也可以不限時,但這種情境較少見。
例如我要監測頁面某個輸入控制項的內容是否有值。而輸入來源可能是多個 Ajax 請求的其中一個。 而且這些 Ajax 請求可能會逾時,我不想讓使用者空等,所以限制這個輸入控制項應該在幾秒內有值。
範例的 expr 引數是 check_data() ,它會查看 id 為 DataInput 的 input 控制項是否有值。 timeout 限時 10 秒。
function check_data()
{
return (document.getElementById('DataInput').value != '');
}
Until(check_data, 10)
.then(_=>{
console.log('data completed.');
})
.catch(_=>{
alert('查詢逾時,請稍候再試');
})