原文地址: await vs return vs return await
做者:Jake Archibald
當編寫異步函數的時候,await
,return
,return await
三者之間有一些區別,從中選取正確的方式是很重要的。
咱們從下面這個異步函數開始:git
async function waitAndMaybeReject(){ // 等待1秒鐘 await new Promise(resolve => setTimeout(resolve, 1000)); // 拋一枚硬幣 const isHeads = Boolean(Math.round(Math.random())); if(isHeads) return 'yay'; throw Error('Boo!'); }
上面的函數會等待1秒鐘後返回一個promise,而後有50%的機會成功返回yay
或者拋出一個error。讓咱們用幾種稍微不一樣的方式使用它。github
async function foo() { try{ waitAndMaybeReject(); }catch(e){ return 'caught'; } }
在此處,若是調用了foo
,返回的promise的狀態始終都是resolved,值也永遠是undefined,並且沒有等待。
因爲咱們沒有await,或者return waitAndMaybeReject()
的結果,因此咱們沒法對它作出任何反應。像這樣的代碼一般是錯誤的。promise
async function foo(){ try{ await waitAndMaybeReject(); }catch(e){ return 'caught'; } }
在此處,若是調用了foo
,返回的promise將始終等待1秒鐘,而後結果要麼狀態爲resolved,值爲undefined,要麼狀態爲resolved,值爲"caught"
。
由於咱們等待了waitAndMaybeReject()
的返回值,因此它的rejection會被返回而且被拋出(throw),catch的代碼塊就會執行。但不管如何,若是waitAndMaybeReject()
沒有報錯而是順利執行,咱們依舊沒法對它的返回值作任何事情。dom
async function foo() { try { return waitAndMaybeReject(); } catch (e) { return 'caught'; } }
在此處,若是調用了foo
,返回的promise將始終等待1秒鐘,而後結果要麼是狀態爲resolved,值爲"yaa"
,要麼是狀態是reject,拋出錯誤Error('Boo!')
。
經過return waitAndMaybeReject()
這行代碼,咱們直接傳遞了它的返回結果,因此咱們的catch代碼塊永遠不會執行。異步
若是你想在try
代碼塊中獲得帶有正確返回值的resolved狀態,在catch
中捕獲異常,那麼正確的選擇就是return await
。async
async function foo() { try { return await waitAndMaybeReject(); } catch (e) { return 'caught'; } }
在此處,若是調用foo
,返回的promise將始終等待1秒鐘,而後結果要麼是狀態爲resolved,值爲"yay"
,要麼是狀態爲resolved,值爲"caught"
由於咱們等待了waitAndMaybeReject()
的結果,因此它的異常rejecttion會被返回而且被拋出(throw),catch的代碼塊就會執行。若是waitAndMaybeReject()
順利執行沒有報錯,就返它的結果。函數
若是對上面的內容仍是覺着困惑,那麼將代碼拆分紅兩個步驟來看可能會比較好理解:eslint
async function foo() { try { // 等待 waitAndMaybeReject() 的結果來解決, // 而且將 fullfill 的值賦給 fullfilledValue: const fulfilledValue = await waitAndMaybeReject(); // 若是 waitAndMaybeReject() reject了, // 咱們的代碼就會拋出異常,而且進入 catch 代碼塊的邏輯。 // 不然,這裏的代碼就會繼續運行下面的語句: return fulfilledValue; } catch (e) { return 'caught'; } }
Note: 在try/catch
以外的代碼塊中執行return await
是多餘的(如前所述,直接return
便可),甚至 Eslint還專門有規則來檢測這種場景,可是在try/catch
代碼塊以內,Eslint就容許這種操做。