面試遇到的問題
當場竟然沒寫出來
let HTTP = {} // request with retry HTTP.doRequestOnce = function(url) { return new Promise((resolve , reject)=>{ let onTimeout = ()=>{ reject('onTimeout') } let xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (4 == xhr.readyState) { if (xhr.status >= 200 && xhr.status < 300) { resolve(xhr.response) } else { reject('request fail') } } }; xhr.open("GET", url, true); xhr.setRequestHeader("CONTENT-TYPE", "application/x-www-form-urlencoded"); xhr.timeout = 5000;// 5s // 網絡層的超時與錯誤統一走超時 onTimeout && (xhr.ontimeout = onTimeout); onTimeout && (xhr.onerror = onTimeout); xhr.send(); }) }; HTTP.doRequestRetry = function(url , times){ console.log('HTTP.doRequestRetry' , url , times) return HTTP.doRequestOnce(url) .then((response)=>{ return Promise.resolve(response) }) .catch((err)=>{ let bRetry = times > 0 return bRetry ? HTTP.doRequestRetry(url , times - 1) : Promise.reject(err) }) }
運行如下(自動重試3次)
同樣原理的setTimeout的超時demo
timeout設置為3.5
因此testClass.setDelays(1 ,2)兩秒后未超時輸出fail
testClass.setDelays(1 ,4)四秒后超時輸出suc

// 超時重試n次的demo /** * 失敗 * testClass.setDelays(1 ,2) .then(()=>{ console.log('suc') }) .catch(()=>{ console.warn('fail') }) VM205:14 setDelays 1 2 undefined Promise {<pending>} VM205:8 setDelay.setTimeout timeTotal 2.5 VM205:14 setDelays 1 1 1 VM205:8 setDelay.setTimeout timeTotal 1.5 VM230:6 fail 成功 testClass.setDelays(1 ,4) .then(()=>{ console.log('suc') }) .catch(()=>{ console.warn('fail') }) VM205:14 setDelays 1 4 undefined Promise {<pending>} VM205:8 setDelay.setTimeout timeTotal 2.5 VM205:14 setDelays 1 3 1 VM205:8 setDelay.setTimeout timeTotal 1.5 VM205:14 setDelays 1 2 2 VM205:8 setDelay.setTimeout timeTotal 0.5 VM205:14 setDelays 1 1 3 VM205:8 setDelay.setTimeout timeTotal -0.5 VM222:3 suc */ let testClass = { timeout : 3.5 , // second 秒后響應是否超時(比較timeout) setDelay : function(second , timePassed = 0){ let timeRemain = testClass.timeout - timePassed return new Promise((resolve , reject)=>{ window.setTimeout(()=>{ timeRemain -= second; console.log('setDelay.setTimeout timeTotal' , timeRemain) resolve(timeRemain < 0) } , second * 1000) }) } , // second 秒后響應是否超時 // 若未超時,重試times次,每次間隔second 秒 setDelays : function(second , times , timePassed = 0){ console.log('setDelays' , second , times , timePassed) let promise = testClass.setDelay(second , timePassed) return promise.then((state)=>{ if(state){ return Promise.resolve() } else if(--times > 0){ return testClass.setDelays(second , times , ++timePassed) } else{ return Promise.reject() } }) } }