動態

詳情 返回 返回

瞭解關鍵區別:await vs return vs return await - 動態 詳情

異步編程是現代 JavaScript 開發中一個重要方面,它使我們能夠處理耗時的操作,而不會阻塞其他任務的執行。使用異步函數時,我們會遇到三個重要的關鍵字:awaitreturnreturn await。在本文中,我們將探討這些關鍵字之間的差異,並討論何時使用每個關鍵字。

在深入探討細節之前,讓我們先闡明一下異步函數的用途。異步函數是一種特殊類型的函數,可以使用 await 關鍵字。它允許我們以更加同步和可讀的方式編寫異步代碼,從而更容易處理 Promise 和執行非阻塞操作。當調用異步函數時,它會返回一個 Promise,該 Promise 解析為函數的最終結果。

現在,讓我們探討一下 awaitreturn、 和 return await 在異步函數上下文中的差異。

讓我們從這個異步函數開始:

async function waitAndMaybeReject() {
  // 等待 1s 
  await new Promise(r => setTimeout(r, 1000));
  // 擲硬幣
  const isHeads = Boolean(Math.round(Math.random()));
  
  if(isHeads) return 'yay';
  throw Error('Boo!');
}

它會返回一個等待一秒的 Promise,然後 50% 的機率以 "yay" 表示,或以錯誤拒絕,讓我們以幾種微妙的方式來使用它。

只是調用

讓我們先來看一下,當我們簡單地調用另一個異步函數而不正確處理返回的 Promise 時,異步函數的行為。請看下面的示例:

async function foo() {
  try {
    waitAndMaybeReject();
  } catch(e) {
    return 'caught';
  }
}

在這裏,如果直接調用 foo,異步函數 foo 返回的 Promise 將始終以 undefined 表示,而無需等待函數 waitAndMaybeReject

因為我們沒有 await 或者 return 異步函數 waitAndMaybeReject() 的結果,因此我們對它沒有作出任何反應,像這樣的代碼通常都是錯誤的。

Await

關鍵字 await 在異步代碼中起着至關重要的作用,它允許我們暫停異步函數的執行,直到承諾得到解決或拒絕,讓我們看看它與僅調用 async 函數有何不同。

await 的本質:

  • 異步代碼同步:await 通過阻塞執行,直到等待的 Promise 被解析或拒絕,簡化了異步代碼的使用。
  • 增強的可讀性:它消除了深度嵌套回調或 then() 長鏈的需要,從而極大地提高了代碼的可讀性。
async function foo() {
  try {
    await waitAndMaybeReject();
    } catch(e) {
    return 'caught';
  }
}

在這裏,如果調用 foo,返回的 Promise 總是會等待一秒,然後以 undefined 或以 "caught" 表示 fulfill

因為我們 await waitAndMaybeReject() 的結果,所以它 rejection 時,將變成錯誤拋出,我們的 catch 代碼塊也將執行。但是,如果 waitAndMaybeReject() 執行完畢,我們不會對值做任何處理。

Return

async function foo() {
  try {
    return waitAndMaybeReject();
  } catch(e) {
    return 'caught';
  }
}

在這裏,如果你調用 foo,返回的 Promise 將始終等待一秒,然後要麼以 "yay" 表示 fulfill,要麼以 Error('Boo!') 表示 reject

由於通過 return waitAndMaybeReject,我們延遲了其結果,因此我們的 catch 代碼塊永遠不會運行。

Return await

try/catch 塊中,你需要的是 return await

retrun await 的本質:

  • 一致的值:return await 可確保函數始終一致的返回 Promise 的解析值,即使在沒有嚴格必要的情況下也是如此,從而確保返回數據類型的一致性。
  • 控制流清晰:在有條件邏輯的情況下,return await 可以提供更清晰的控制流,從而更容易跟蹤代碼的執行路徑。
async function foo() {
  try {
    return await waitAndMaybeReject();
  } catch(e) {
    return 'caught';
  }
}

在這裏,如果調用 foo,將始終等待一秒後返回 Promise,然後以 "yay" 或者以 "caught" 表示 fulfill

因為我們等待 waitAndMaybeReject() 的結果,所以它的 rejection 將變成拋出的 throw,我們的 catch 代碼塊將執行。如果 waitAndMaybeReject() 執行完畢,我們將返回其結果。

如果上述內容看起來令人困惑,那麼將其視為兩個獨立的步驟可能會更容易理解:

async function foo() {
  try {
    // 等待 waitAndMaybeReject() 的結果結算,
        // 並將已完成的值分配給 fulfilledValue:
    const fulfillValue = await waitAndMaybeReject();
    // 如果 waitAndMaybeReject() 的結果被拒絕,我們的代碼就會拋出,然後跳到 catch 塊。
    // 否則,此塊將繼續運行:
    return fulfillValue;
  } catch(e) {
    return 'caught';
  }
}

注意:在 try/catch 塊之外,return await 是多餘的,ESLint 甚至有一條規則來檢測它,但它允許在 try/catch 中使用。

參考:

  • https://jakearchibald.com/2017/await-vs-return-vs-return-await/
  • https://levelup.gitconnected.com/understanding-the-crucial-di...
user avatar toopoo 頭像 grewer 頭像 Leesz 頭像 smalike 頭像 linlinma 頭像 freeman_tian 頭像 jingdongkeji 頭像 qingzhan 頭像 kobe_fans_zxc 頭像 dirackeeko 頭像 aqiongbei 頭像 littlelyon 頭像
點贊 225 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.