高階函式的使用
問題
位元組跳動面試時問題:原函式例如fetchData是一個非同步函式,嘗試從伺服器端獲取一些資訊並返回一個Promise。寫一個新的函式可以自動重試一定次數,並且在使用上和原函式沒有區別。
思路
這個問題其實不是很難,不過可能是
緊張的原因,當時答得不是很好。不過思路還是很明確的,內部通過閉包來計數,一旦成功獲得資料就返回,否則就繼續嘗試,知道重試次數達到上限位置。
function retry(fetch, n) { let i = 0 function tryFetch(err) { if (i > n) { return "reach try limit:" + err } else { fetch().then(data => { return data }).catch(err => { i ++ tryFetch(err) }) } } }
當時差不多就是那麼答的,有幾個問題是,函式呼叫方式與原來不通,按道理應該返回一個Promise,更準確的說是返回一個返回Promise的函式,如果有什麼問題也應該在外面能catch住。另一方面,也許fetch函式要接受引數,也應該傳遞進去才行。
解決
修改後的函式如下
function retry(fetch, n) { return function() { let args = arguments return new Promise((rseolve, reject) => { let i = 0 tryFetch() function tryFetch(err) { console.log(i) if (i > n) { reject("reach max try" + err) } else { fetch(...args).then(data => { rseolve(data) }).catch(err => { i ++ tryFetch(err) }) } } }) } }
最後自己寫了個fetch進行測試
function fetch() { console.log(arguments) return new Promise((rseolve, reject) => { console.log('trying...') setTimeout(function() { if (Math.random() > 0.9) { console.log('resolved') rseolve('resolved') } else { console.log('rejected') reject('rejected') } }, 5000) }) }
結果符合預期,問題解決。當然也可以返回async function,不過和Promise本質上是一個思路。