深刻js的Error關鍵字

錯誤定位是開發中的一項必備的重要能力,咱們來看下在前端開發中v8爲咱們提供的Error關鍵字前端

Error做爲函數使用

當像函數同樣使用 Error 時 -- 若是沒有 new,它將返回一個 Error 對象。因此, 僅僅調用 Error 將產生與經過new 關鍵字構造 Error 對象的輸出相同。webpack

// this:
const x = Error('I was created using a function call!');
​​​​// has the same functionality as this:
const y = new Error('I was constructed via the "new" keyword!');
複製代碼

Error 類型

除了通用的Error構造函數外,JavaScript還有6個其餘類型的錯誤構造函數web

  • EvalError 建立一個error實例,表示錯誤的緣由:與 eval() 有關。
  • InternalError 建立一個表明Javascript引擎內部錯誤的異常拋出的實例。 如: "遞歸太多".
  • RangeError 建立一個error實例,表示錯誤的緣由:數值變量或參數超出其有效範圍。
  • ReferenceError 建立一個error實例,表示錯誤的緣由:無效引用。
  • SyntaxError 建立一個error實例,表示錯誤的緣由:eval()在解析代碼的過程當中發生的語法錯誤。
  • TypeError 建立一個error實例,表示錯誤的緣由:變量或參數不屬於有效類型。
  • URIError 建立一個error實例,表示錯誤的緣由:給 encodeURI()或 decodeURl()傳遞的參數無效。

建立V8時拋出的全部內部錯誤都將捕獲堆棧跟蹤。能夠經過非標準error.stack屬性從JavaScript訪問此堆棧跟蹤。V8還具備各類鉤子,用於控制如何收集和格式化堆棧跟蹤,並容許自定義錯誤也收集堆棧跟蹤。本文檔概述了V8的JavaScript堆棧跟蹤API。api

基本堆棧跟蹤

默認狀況下,V8引起的幾乎全部錯誤都具備一個stack屬性,該屬性保存最頂層的10個堆棧幀,格式爲字符串。這是一個徹底格式化的堆棧跟蹤的示例: 函數

在這裏插入圖片描述

改變堆棧幀數

堆棧跟蹤是在建立錯誤時收集的,而且不管在何處或拋出錯誤的次數都相同。咱們收集10幀,由於一般它足以有用,但數量很少,會對性能產生明顯的負面影響。能夠經過設置變量來控制收集多少堆棧幀性能

Error.stackTraceLimit
複製代碼

將其設置爲0禁用堆棧跟蹤收集。任何有限的整數值均可以用做要收集的最大幀數。設置爲Infinity表示將收集全部幀。該變量僅影響當前上下文。必須爲每一個須要不一樣值的上下文顯式設置它。ui

注意Error.stackTraceLimit是一個非標準的api 請勿在生產環境下使用this

堆棧跟蹤收集自定義異常

用於堆棧錯誤的堆棧跟蹤機制是使用通用堆棧跟蹤收集API來實現的,該API也可用於用戶腳本spa

Error.captureStackTrace(error, constructorOpt)
複製代碼

將堆棧屬性添加到給定的error對象,該屬性在調用時產生堆棧跟蹤captureStackTrace。收集的堆棧跟蹤信息Error.captureStackTrace將當即收集,格式化並附加到給定的error對象。3d

可選constructorOpt參數容許您傳遞函數值。收集堆棧跟蹤時,對該函數最頂層調用(包括該調用)上方的全部幀均不包含在堆棧跟蹤中。這對於隱藏對用戶無用的實現細節頗有用。定義捕獲堆棧跟蹤的自定義錯誤的一般方法是:

function MyError() {
  Error.captureStackTrace(this, MyError);
  // Any other initialization goes here.
}
console.log(new MyError().stack);
複製代碼

這樣將會忽略堆棧中的函數調用棧信息

在這裏插入圖片描述
若是須要展現函數調用棧信息的話則去掉參數中的構造函數
在這裏插入圖片描述

使用場景

因爲Error.captureStackTrace()能夠返回調用堆棧信息,所以在自定義Error類的內部常常會使用該函數,用以在error對象上添加合理的stack屬性。上文中的MyError類便是一個最簡單的例子。

爲了避免向使用者暴露自定義Error類的內部細節,在自定義Error類內部使用captureStackTrace時,每每會傳入constructorOpt參數,其值即爲自定義 Error類的構造函數。具體作法有3種:

  1. Error.captureStackTrace(this, MyError); 將構造函數的變量名做爲constructorOpt參數傳入。這一作法比較簡單、直接,但不利之處也比較明顯:代碼所要傳達的是「忽略當前構造函數及其內部的堆棧調用信息」,而以具體的構造函數做爲參數傳入使得這一語句缺少通用性,不利於程序的進一步抽象。
  2. Error.captureStackTrace(this, this.constructor); 經過this.constructor傳入constructorOpt參數。與上一種方法相比,這一方式更具通用性。在自定義Error類中使用captureStackTrace時,推薦採用該方法webpack的錯誤捕獲對象 WebpackError就是這麼幹的
"use strict";

const inspect = require("util").inspect.custom;

class WebpackError extends Error {
	/** * Creates an instance of WebpackError. * @param {string=} message error message */
	constructor(message) {
		super(message);

		this.details = undefined;
		this.missing = undefined;
		this.origin = undefined;
		this.dependencies = undefined;
		this.module = undefined;

		Error.captureStackTrace(this, this.constructor);
	}

	[inspect]() {
		return this.stack + (this.details ? `\n${this.details}` : "");
	}
}

module.exports = WebpackError;
複製代碼
  1. Error.captureStackTrace(this, arguments.callee);經過arguments.callee將「當前函數」做爲constructorOpt參數傳入。不過,因爲ES5的strict模式中禁用了arguments.callee,所以不建議使用該寫法。

除了自定義Error類的使用場景,在JavaScript程序中,當須要獲知調用堆棧信息時,均可以經過調用Error.captureStackTrace()來實現。以往若是須要獲知調用堆棧信息,通常的作法是拋出一個Error對象並當即加以捕捉,經過訪問該對象的stack屬性來得到調用堆棧。一個簡單的例子以下

try {
  throw new Error();
} catch (e) {
  // e.stack 中包含了堆棧數據,能夠進行處理從而忽略不感興趣的堆棧信息
}
複製代碼

與這種作法相比,能夠很明顯的看到,使用Error.captureStackTrace()會更簡潔、易用,也更優雅;而這,也許就是V8中添加Error.captureStackTrace()的緣由。

相關文章
相關標籤/搜索