高階函數的使用

問題

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章