博客 / 詳情

返回

async/await 到底要不要加 try catch?我來給你整明白!

🧑‍💻 寫在開頭

點贊 + 收藏 === 學會🤣🤣🤣

前言

現在寫異步代碼,基本上就是 Promiseasync/await 兩種寫法。雖然這倆都能幹同樣的活,但 async/await 寫起來更像同步代碼,讀起來更順眼,所以很多人都説它是"異步編程的終極方案"。

不過有個問題挺讓人糾結的:用 async/await 的時候,到底要不要加 try catch 來抓錯誤?我看了好多項目代碼,發現大家做法都不一樣,有的加有的不加,甚至有的連 catch 都不寫,這就很迷了。

先看幾種寫法

寫法1:老實用 try catch

function getUserInfo () {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('請求出錯了哦')
        }, 1000)
    })
}

async function logined () {
    try {
        let userInfo = await getUserInfo()
        // 如果上面出錯了,這裏就不會執行了
        let pageInfo = await getPageInfo(userInfo?.userId)
    } catch(e) {
        console.warn('抓到一個錯誤:', e)
    }
}

logined()

這種寫法的好處是錯誤能抓住,而且代碼會在出錯的地方停下來,不會繼續往下執行。缺點就是 try catch 佔了太多行數,每個接口都這麼寫的話,代碼看起來有點囉嗦。

寫法2:直接在後面接 .catch()

function getUserInfo () {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('請求出錯了哦')
        }, 1000)
    })
}

async function logined () {
    let userInfo = await getUserInfo().catch(e => console.warn('抓到一個錯誤:', e))
    // 注意:這裏即使出錯了也會繼續執行!
    if (!userInfo) return // 所以得手動檢查一下
    let pageInfo = await getPageInfo(userInfo?.userId)
}

logined()

這種寫法也能抓住錯誤,但是程序不會自動停下來,還會繼續往下走。所以你得自己檢查 userInfo 是不是空的,不然可能會出問題。

寫法3:在 catch 裏再 reject

function getUserInfo () {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('請求出錯了哦')
        }, 1000)
    })
}

async function logined () {
    let userInfo = await getUserInfo().catch(e => {
        console.warn('抓到一個錯誤:', e)
        return Promise.reject(e) // 這裏再扔出去一次
    })
    // 這樣就會停在這裏了
    let pageInfo = await getPageInfo(userInfo?.userId)
}

logined()

這種寫法能讓程序在出錯的地方停下來,但是會在控制枱留下一個 "uncaught (in promise)" 的錯誤提示,有些人覺得這樣不太好看。

到底該用哪種?

其實在真實項目裏,我們一般會用 axios 或 fetch 這些庫來發請求,通常會對它們進行一層封裝。在封裝的時候就可以統一處理錯誤了。

至於要不要在 await 後面加 try catch,主要看你想不想讓程序在出錯的時候停下來:

  • 不想中斷程序,可以這樣寫:

let userInfo = await getUserInfo().catch(e => console.warn(e))
if (!userInfo) return // 記得檢查一下是不是空的

這樣控制枱不會報紅字錯誤。

  • 想中斷程序,又不想看控制枱報錯,就用 try catch:
try {
    let userInfo = await getUserInfo()
    let pageInfo = await getPageInfo(userInfo?.userId)
} catch(e) {
    console.warn(e)
}
  • 想中斷程序,又不介意控制枱報錯:
let userInfo = await getUserInfo().catch(e => {
    console.warn(e)
    return Promise.reject(e)
})
// 這裏會停下來
let pageInfo = await getPageInfo(userInfo?.userId)

我的建議

從我個人的使用體驗來看,try catch 是最好的選擇

  • 代碼邏輯更清晰,更像同步代碼的寫法
  • 錯誤處理集中在一個地方,好管理
  • 控制枱不會出現一堆難看的 "uncaught (in promise)" 錯誤
  • 符合直覺:出錯了就應該停下來

雖然 try catch 會讓代碼多幾行,但是比起代碼的可讀性和可維護性,這點代價是值得的。

既然都已經用 async/await 來寫同步風格的代碼了,那就乾脆用到底,用 try catch 來處理錯誤,這樣代碼風格更統一,讀起來也更舒服。

如果對您有所幫助,歡迎您點個關注,我會定時更新技術文檔,大家一起討論學習,一起進步。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.