問題
位元組跳動面試時問題:原函式例如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本質上是一個思路。