最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript利用Error.cause進行錯誤調(diào)試的方法詳解

 更新時間:2025年11月26日 08:19:19   作者:冴羽  
在 JavaScript 中,拋出錯誤很容易,但追溯原因卻有些麻煩,這就是 cause屬性的用武之地,下面小編就和大家詳細介紹一下具體的調(diào)試方法吧

1. 前言

在 JavaScript 中,拋出錯誤很容易,但追溯原因卻有些麻煩,這就是 cause屬性的用武之地。

這是我們傳統(tǒng)的處理錯誤的做法:

try {
  JSON.parse("{ bad json }");
} catch (err) {
  throw new Error("Something went wrong: " + err.message);
}

雖然包裝了錯誤,但已經(jīng)丟失了原始的堆棧信息和錯誤類型。

當問題發(fā)生時,你只能看到最頂層的錯誤信息,卻不知道根本原因是什么。

你好,我是冴羽。前端資訊、前端干貨,歡迎關(guān)注公眾號:冴羽

2. 引入 Error.cause

ES2022 引入了 Error.cause 屬性,可以保留原始錯誤信息:

try {
  try {
    JSON.parse("{ bad json }");
  } catch (err) {
    throw new Error("Something went wrong", { cause: err });
  }
} catch (err) {
  console.error(err.stack);
  console.error("Caused by:", err.cause.stack);
}

此時你可以看到完整的錯誤鏈:

Error: Something went wrong
    at ...
Caused by: SyntaxError: Unexpected token b in JSON at position 2
    at JSON.parse (<anonymous>)
    at ...

現(xiàn)在,你既保留了原始錯誤,又能提供清晰的頂層錯誤信息。

3. 實際應(yīng)用示例

讓我們看一個更實際的例子:

function fetchUserData() {
  try {
    JSON.parse("{ broken: true }"); // ← 這里會失敗
  } catch (parseError) {
    throw new Error("Failed to fetch user data", { cause: parseError });
  }
}

try {
  fetchUserData();
} catch (err) {
  console.error(err.message); // "Failed to fetch user data"
  console.error(err.cause); // [SyntaxError: Unexpected token b in JSON]
  console.error(err.cause instanceof SyntaxError); // true
}

可以看到代碼非常清晰直觀。

而且 cause 屬性被定義為不可枚舉,因此它不會污染日志或 for...in 循環(huán),除非你顯式訪問它。

4. 自定義錯誤類

你可以在自定義錯誤類中使用 cause 屬性:

class DatabaseError extends Error {
  constructor(message, { cause } = {}) {
    super(message, { cause });
    this.name = "DatabaseError";
  }
}

如果你的運行環(huán)境是 ES2022+,這已經(jīng)足夠了:super(message, { cause }) 會自動處理一切。

對于 TypeScript 用戶,確保 tsconfig.json 配置了:

{
  "compilerOptions": {
    "target": "es2022",
    "lib": ["es2022"]
  }
}

否則,在將 { cause } 傳遞給 Error 構(gòu)造函數(shù)時可能會看到類型錯誤。

5. 更好的測試斷言

假設(shè)你的服務(wù)拋出了一個 UserCreationError,這是由一個 ValidationError 引發(fā)的。

你可以這樣寫斷言:

expect(err.cause).toBeInstanceOf(ValidationError);

這樣測試會更清晰、更健壯。

6. 注意事項

默認情況下,console.error(err) 只會打印頂層錯誤。cause鏈不會自動顯示,因此需要手動打?。?/p>

console.error(err);
console.error("Caused by:", err.cause);

盡管 cause 很好,但也不要濫用。每個小錯誤都包裝可能更亂,因此只在真正需要上下文的時候使用。

7. 遞歸打印完整錯誤鏈

這是一個安全遍歷錯誤鏈的工具函數(shù):

function logErrorChain(err, level = 0) {
  if (!err) return;
  console.error(" ".repeat(level * 2) + `${err.name}: ${err.message}`);

  if (err.cause instanceof Error) {
    logErrorChain(err.cause, level + 1);
  } else if (err.cause) {
    console.error(" ".repeat((level + 1) * 2) + String(err.cause));
  }
}

如果需要完整堆棧信息:

function logFullErrorChain(err) {
  let current = err;
  while (current) {
    console.error(current.stack);
    current = current.cause instanceof Error ? current.cause : null;
  }
}

對于結(jié)構(gòu)復雜、可能在不同層級出現(xiàn)多種故障的系統(tǒng)來說,這非常有用。

8. 跨層錯誤鏈示例

假設(shè)調(diào)用流程如下:

  • 數(shù)據(jù)庫連接失敗,拋出 ConnectionTimeoutError
  • 捕獲后包裝成 DatabaseError
  • 再次捕獲并包裝成 ServiceUnavailableError
class ConnectionTimeoutError extends Error {}
class DatabaseError extends Error {}
class ServiceUnavailableError extends Error {}

try {
  try {
    try {
      throw new ConnectionTimeoutError("DB connection timed out");
    } catch (networkErr) {
      throw new DatabaseError("Failed to connect to database", { cause: networkErr });
    }
  } catch (dbErr) {
    throw new ServiceUnavailableError("Unable to save user data", { cause: dbErr });
  }
} catch (finalErr) {
  logErrorChain(finalErr);
}

控制臺輸出:

ServiceUnavailableError: Unable to save user data
  DatabaseError: Failed to connect to database
    ConnectionTimeoutError: DB connection timed out

可以看到,錯誤鏈提供了一個清晰的視圖,告訴你發(fā)生了什么以及在哪里發(fā)生的。

9. 支持度

.cause 參數(shù)在所有現(xiàn)代環(huán)境中都支持:

  • Chrome 93+、Firefox 91+、Safari 15+、Edge 93+
  • Node.js 16.9+
  • Bun 和 Deno(當前版本)

需要注意的是,開發(fā)者工具可能不會自動顯示 cause。

所以需要顯式記錄它(console.error('Caused by:', err.cause))。

還要注意:如果使用 Babel 或 TypeScript 進行轉(zhuǎn)譯,此功能不會被 polyfill。

10. 異步操作中的錯誤處理

Error.cause 同樣適用于異步操作。結(jié)合 async/await 可以這樣使用:

async function fetchData() {
  try {
    const response = await fetch("/api/data");
    if (!response.ok) {
      throw new Error(`HTTP error! Status: ${response.status}`);
    }
    return await response.json();
  } catch (error) {
    console.error("數(shù)據(jù)獲取失敗:", error);
    throw new Error("Failed to fetch data", { cause: error });
  }
}

這種方式讓異步代碼的錯誤處理邏輯看起來與同步代碼無異,大大提升了可讀性和可維護性。

11. 總結(jié)

總結(jié)一下,現(xiàn)代錯誤鏈處理的最佳實踐

  • 使用 new Error(message, { cause }) 保留上下文
  • 適用于內(nèi)置錯誤類和自定義錯誤類
  • 所有現(xiàn)代運行時環(huán)境都支持(瀏覽器、Node.js、Deno、Bun)
  • 可以改善日志、調(diào)試和測試斷言
  • 注意 TypeScript:設(shè)置 "target": "es2022""lib": ["es2022"]
  • 注意記錄 err.cause 或手動遍歷錯誤鏈

從而實現(xiàn)更清晰的堆棧跟蹤、更好的上下文、更愉快的調(diào)試體驗。

Error.cause 就是你錯誤處理中缺少的那一環(huán)。

到此這篇關(guān)于JavaScript利用Error.cause進行錯誤調(diào)試的方法詳解的文章就介紹到這了,更多相關(guān)JavaScript錯誤調(diào)試內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

托克托县| 嵩明县| 两当县| 景德镇市| 临高县| 涞水县| 屏边| 治多县| 类乌齐县| 勐海县| 湘阴县| 石狮市| 成安县| 台东县| 深圳市| 集安市| 东乡县| 通辽市| 雅江县| 新巴尔虎右旗| 嘉鱼县| 兰西县| 宜章县| 博乐市| 凌源市| 来凤县| 贵南县| 乌兰浩特市| 西平县| 久治县| 五台县| 瑞昌市| 绥中县| 临江市| 乐平市| 南京市| 策勒县| 保亭| 连南| 邛崃市| 寿宁县|