自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

函數(shù)式 try-catch 如何轉變 JavaScript 代碼

開發(fā) 前端
我們并沒有丟棄它,而是將其轉化為更易維護和可預測的工具。 tryCatch()? 甚至只是許多使用像 try-catch 這樣的命令式構造的聲明式友好函數(shù)之一

這種情況有多常見?

function writeTransactionsToFile(transactions) {
  let writeStatus;
  try {
    fs.writeFileSync('transactions.txt', transactions);
    writeStatus = 'success';
  } catch (error) {
    writeStatus = 'error';
  }
  
  // do something with writeStatus...
}

這是另一個我們想要一個取決于是否存在異常的值的實例。

通常, 我們可能會在 try-catch 的范圍之外創(chuàng)建一個可變變量,以便在其中和之后無錯誤地訪問。

但情況并非總是這樣。只要有一個函數(shù)式的 try-catch 就不會這樣。

一個純粹的 tryCatch() 函數(shù)避免了可變變量,并在我們的代碼庫中鼓勵可維護性和可預測性。

沒有修改外部狀態(tài) - tryCatch() 封裝了整個錯誤處理邏輯并產生單一輸出。

我們的 catch 變成了一個不需要大括號的單行代碼:

function writeTransactionsToFile(transactions) {
  // 我們現(xiàn)在可以使用 const 了
  const writeStatus = tryCatch({
    tryFn: () => {
      fs.writeFileSync('transactions.txt', transactions);
      return 'success';
    },
    catchFn: (error) => 'error'
  });

  // do something with writeStatus...
}

tryCatch() 函數(shù)

那么,這個 tryCatch() 函數(shù)究竟是什么樣子的呢?

從我們以上的使用方式,你已經(jīng)可以猜到定義了:

function tryCatch({ tryFn, catchFn }) {
  try {
    return tryFn();
  } catch (error) {
    return catchFn(error);
  }
}

為了正確地講述函數(shù)的作用,我們確保使用對象參數(shù)來明確參數(shù)名稱——即使只有兩個屬性。

因為編程不僅僅是達到目的的手段 - 我們還在講述從開始到結束的代碼庫中的對象和數(shù)據(jù)的故事。

TypeScript 在這樣的情況下非常好用;我們看看一個泛型類型的 tryCatch() 可能是什么樣子:

type TryCatchProps<T> = {
  tryFn: () => T;
  catchFn: (error: any) => T;
};

function tryCatch<T>({ tryFn, catchFn }: TryCatchProps<T>): T {
  try {
    return tryFn();
  } catch (error) {
    return catchFn(error);
  }
}

我們用 TypeScript 重寫功能性 writeTransactionsToFile() :

function writeTransactionsToFile(transactions: string) {
  // 返回 'success' 或 'error'
  const writeStatus = tryCatch<'success' | 'error'>({
    tryFn: () => {
      fs.writeFileSync('transaction.txt', transactions);
      return 'success';
    },
    catchFn: (error) => return 'error';
  });

  // do something with writeStatus...
}

我們使用 'success' | 'error' 聯(lián)合類型來限制我們可以從 try 和 catch 回調中返回的字符串。

異步處理

不,我們完全不需要擔心這個問題 - 如果 tryFn 或 catchFn 是 async ,那么 writeTransactionToFile() 會自動返回一個 Promise 。

這是我們大多數(shù)人應該熟悉的另一個 try-catch 情況:發(fā)出網(wǎng)絡請求并處理錯誤。

在這里,我們根據(jù)請求是否成功來設置一個外部變量(在try-catch 之外)——在 React 應用中,我們可以輕松地用它設置狀態(tài)。

顯然,在真實世界的應用程序中,請求將會是異步的,以避免阻塞用戶界面線程:

async function comment(comment: string) {
  type Status = 'error' | 'success';
  let commentStatus: Status;
  try {
    const response = await fetch('https://api.mywebsite.com/comments', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ comment }),
    });

    if (!response.ok) {
      commentStatus = 'error';
    } else {
      commentStatus = 'success';
    }
  } catch (error) {
    commentStatus = 'error';
  }

  // do something with commentStatus...
}

我們再次需要在這里創(chuàng)建一個可變變量,以便它可以進入 try-catch 并且沒有作用域錯誤地成功出來。

我們像以前一樣進行重構,這次,我們 async 了 try 和 catch 函數(shù),從而 await 了 tryCatch() :

async function comment(comment: string) {
  type Status = 'error' | 'success';
  // ?? await because this returns Promise<Status>
  const commentStatus = await tryCatch<Status>({
    tryFn: async () => {
      const response = await fetch('https://api.mywebsite.com/comments', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ comment }),
      });
      // ?? functional conditional
      return response.ok ? 'success' : 'error';
    },
    catchFn: async (error) => 'error',
  });

  // do something with commentStatus...
}

可讀性,模塊化,和單一職責

處理異常時遵循的兩個 try-catch 經(jīng)驗法則:

  • try-catch 應盡可能靠近錯誤的源頭
  • 每個函數(shù)只使用一個 try-catch

他們將使你的代碼在短期和長期內更易于閱讀和維護??纯催@里的 processJSONFile() ??,它遵守了規(guī)則 1。

第一個 try-catch 僅負責處理文件讀取錯誤,沒有其他功能。不會再向 try 添加任何邏輯,所以 catch 也永遠不會改變。

接下來的 try-catch 就在這里處理 JSON 解析。

function processJSONFile(filePath) {
  let contents;
  let jsonContents;

  // ? 第一個 try-catch 塊,用于處理文件讀取錯誤
  try {
    contents = fs.readFileSync(filePath, 'utf8');
  } catch (error) {
    // 在這里記錄錯誤
    contents = null;
  }

  // ? 第二個 try-catch 塊,用于處理 JSON 解析錯誤
  try {
    jsonContents = JSON.parse(contents);
  } catch (error) {
    // 在這里記錄錯誤
    jsonContents = null;
  }

  return jsonContents;
}

但是 processJsonFile() 完全無視規(guī)則 2,同一個函數(shù)中的 try-catch 塊都在。

那么,我們通過將它們重構為各自的函數(shù)來解決這個問題:

function processJSONFile(filePath) {
  const contents = getFileContents(filePath);
  const jsonContents = parseJSON(contents);

  return jsonContents;
}

function getFileContents(filePath) {
  let contents;
  try {
    contents = fs.readFileSync(filePath, 'utf8');
  } catch (error) {
    contents = null;
  }
  return contents;
}

function parseJSON(content) {
  let json;
  try {
    json = JSON.parse(content);
  } catch (error) {
    json = null;
  }
  return json;
}

但是我們現(xiàn)在有 tryCatch() - 我們可以做得更好:

function processJSONFile(filePath) {
  return parseJSON(getFileContents(filePath));
}

const getFileContents = (filePath) =>
  tryCatch({
    tryFn: () => fs.readFileSync(filePath, 'utf8'),
    catchFn: () => null,
  });

const parseJSON = (content) =>
  tryCatch({
    tryFn: () => JSON.parse(content),
    catchFn: () => null,
  });

我們正在做的只不過是消除異?!@就是這些新功能的主要工作。

如果這種情況經(jīng)常發(fā)生,為什么不創(chuàng)建一個“靜音器”版本,在成功時返回 try 函數(shù)的結果,或者在錯誤時什么也不返回?

function tryCatch<T>(fn: () => T) {
  try {
    return fn();
  } catch (error) {
    return null;
  }
}

將我們的代碼進一步縮短為這樣:

function processJSONFile(filePath) {
  return parseJSON(getFileContents(filePath));
}

const getFileContents = (filePath) => 
  tryCatch(() => fs.readFileSync(filePath, 'utf8'));

const parseJSON = (content) => 
  tryCatch(() => JSON.parse(content));

附注:在命名標識符時,我建議我們盡可能地使用名詞來表示變量,形容詞來表示函數(shù),而對于高階函數(shù)……我們可以使用副詞!就像一個故事,代碼將更自然地閱讀,并可能更好地理解。

所以,我們可以使用 silently ,而不是 tryCatch :

const getFileContents = (filePath) => 
  silently(() => fs.readFileSync(filePath, 'utf8'));

const parseJSON = (content) => 
  silently(() => JSON.parse(content));

總結

當然, try-catch 本身就能完美運行。

我們并沒有丟棄它,而是將其轉化為更易維護和可預測的工具。 tryCatch() 甚至只是許多使用像 try-catch 這樣的命令式構造的聲明式友好函數(shù)之一

如果更喜歡直接使用 try-catch ,請記住使用 2 個 try-catch 的經(jīng)驗法則,以提高您的代碼的模塊化和可讀性。

責任編輯:武曉燕 來源: 大遷世界
相關推薦

2024-05-24 08:59:15

2025-01-16 12:00:00

try-catchfor循環(huán)

2024-11-04 08:20:00

try-catch編程

2009-07-21 14:30:38

Scalatry-catch

2025-04-29 08:05:00

JavaScript錯誤處理開發(fā)

2020-05-29 08:14:49

代碼Try-Catch程序員

2025-02-12 12:00:00

前端try-catchJavaScrip

2024-12-02 11:07:24

Java代碼機制

2020-10-14 12:10:22

Javatry-catch代碼

2024-05-07 07:58:47

C#程序類型

2017-11-02 15:26:10

JavaScriptasync錯誤

2022-01-25 12:14:39

面試try-catch代碼

2020-08-24 13:35:59

trycatchJava

2024-11-13 01:00:18

asyncawait?編程

2020-09-27 07:48:40

不用try catch

2023-05-16 15:32:45

JavaScriptWeb前端工程師

2023-11-13 17:01:26

C++編程

2009-12-02 19:56:33

PHP中try{}ca

2009-04-10 13:48:17

JavaScripteval全局代碼

2023-09-07 07:53:21

JavaScriptGoRust
點贊
收藏

51CTO技術棧公眾號