亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript中錯誤異常的案例

發布時間:2020-10-14 15:46:04 來源:億速云 閱讀:242 作者:小新 欄目:web開發

這篇文章將為大家詳細講解有關JavaScript中錯誤異常的案例,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

我的建議是不要隱藏錯誤,勇敢地拋出來。沒有人會因為代碼出現 bug 導致程序崩潰而羞恥,我們可以讓程序中斷,讓用戶重來。錯誤是無法避免的,如何去處理它才是最重要的。

JavaScript 提供一套錯誤處理機制,錯誤是干擾程序正常流程的非正常的事故。而沒人可以保持程序沒有 bug,那么上線后遇到特殊的 bug,如何更快的定位問題所在呢?這就是我們這個專題需要討論的問題。

下面會從 JavaScript Error 基礎知識、如何攔截和捕獲異常、如何方便的在線上報錯誤等方面來敘述,本人也是根據網上的知識點進行了一些總結和分析(我只是互聯網的搬運工,不是創造者),如果有什么錯漏的情況,請在 issue 上狠狠的批評我。

這個專題目前是針對瀏覽器的,還沒考慮到 node.js,不過都是 JavaScript Es6 語法,大同小異。

什么時候 JavaScript 會拋出錯誤呢?

一般分為兩種情況:

JavaScript 自帶錯誤

開發者主動拋出的錯誤

JavaScript 引擎自動拋出的錯誤

大多數場景下我們遇到的錯誤都是這類錯誤。如果發生Javscript 語法錯誤、代碼引用錯誤、類型錯誤等,JavaScript 引擎就會自動觸發此類錯誤。如下一些場景:

場景一

console.log(a.notExited)
// 瀏覽器會拋出 Uncaught ReferenceError: a is not defined

場景二

const a;
// 瀏覽器拋出 Uncaught SyntaxError: Missing initializer in const declaration

語法錯誤,瀏覽器一般第一時間就拋出錯誤,不會等到執行的時候才會報錯。

場景三

let data;
data.forEach(v=>{})
// Uncaught TypeError: Cannot read property 'forEach' of undefined

手動拋出的錯誤

一般都是類庫開發的自定義錯誤異常(如參數等不合法的錯誤異常拋出)。或者重新修改錯誤 message 進行上報,以方便理解。

場景一

function sum(a,b){
  if(typeof a !== 'number') {
    throw TypeError('Expected a to be a number.');
  }
  if(typeof b !== 'number') {
    throw TypeError('Expected b to be a number.');
  }
  return a + b;
}
sum(3,'d');
// 瀏覽器拋出 uncaught TypeError: Expected b to be a number.

場景二

當然我們不一定需要這樣做。

let data;

try {
  data.forEach(v => {});
} catch (error) {
  error.message = 'data 沒有定義,data 必須是數組。';
  error.name = 'DataTypeError';
  throw error;
}

如何創建 Error 對象?

創建語法如下:

new Error([message[,fileName,lineNumber]])

省略 new 語法也一樣。

其中fileName 和 lineNumber 不是所有瀏覽器都兼容的,谷歌也不支持,所以可以忽略。

Error 構造函數是通用錯誤類型,除了 Error 類型,還有 TypeError、RangeError 等類型。

Error 實例

這里列舉的都是 Error 層的原型鏈屬性和方法,更深層的原型鏈的繼承屬性和方便不做說明。一些有兼容性的而且不常用的屬性和方法不做說明。

console.log(Error.prototype)
// 瀏覽器輸出 {constructor: ?, name: "Error", message: "", toString: ?}

其他錯誤類型構造函數是繼承 Error,實例是一致的。

屬性

Error.prototype.message

錯誤信息, Error("msg").message === "msg"。

Error.prototype.name

錯誤類型(名字), Error("msg").name === "Error”。如果是 TypeError,那么 name 為 TypeError。

Error.prototype.stack

Error 對象作為一個非標準的棧屬性提供了一種函數追蹤方式。無論這個函數被被調用,處于什么模式,來自于哪一行或者哪個文件,有著什么樣的參數。這個棧產生于最近一次調用最早的那次調用,返回原始的全局作用域調用。

這個不是規范,存在兼容性。經測試,谷歌、火狐、Edge、safar 都支持此特性(都是在最新的版本下測試 2019-04-02),IE 不支持。

方法

Error.prototype.constructor

Error.prototype.toString

返回值格式為 ${name}: ${message}。

常用 Error 類型

除了通用的 Error 構造函數外,JavaScript還有常見的 5 個其他類型的錯誤構造函數。

TypeError

創建一個 Error 實例,表示錯誤的原因:變量或參數不屬于有效類型。

throw TypeError("類型錯誤");
// Uncaught TypeError: 類型錯誤

RangeError

創建一個 Error 實例,表示錯誤的原因:數值變量或參數超出其有效范圍。

throw RangeError("數值超出有效范圍");
// Uncaught RangeError: 數值超出有效范圍

ReferenceError

創建一個 Error 實例,表示錯誤的原因:無效引用。

throw ReferenceError("無效引用");
// Uncaught ReferenceError: 無效引用

SyntaxError

創建一個 Error 實例,表示錯誤的原因:語法錯誤。這種場景很少用,除非類庫定義了新語法(如模板語法)。

throw SyntaxError("語法錯誤");
// Uncaught SyntaxError: 語法錯誤

URIError

創建一個 Error 實例,表示錯誤的原因:涉及到 uri 相關的錯誤。

throw URIError("url 不合法");
// Uncaught RangeError: url 不合法

自定義 Error 類型

自定義新的 Error 類型需要繼承 Error ,如下自定義 CustomError:

function CustomError(...args){
  class InnerCustomError extends Error {
    name = "CustomError";
  }
  return new InnerCustomError(...args);
}

繼承 Error 后,我們只需要對 name 做重寫,然后封裝成可直接調用的函數即可。

如何攔截 JavaScript 錯誤?

既然沒人能保證 web 應用不會出現 bug,那么出現異常報錯時,如何攔截并進行一些操作呢?

try…catch… 攔截

這是攔截 JavaScript 錯誤,攔截后,如果不手動拋出錯誤,這個錯誤將靜默處理。平常寫代碼如果我們知道某段代碼可能會出現報錯問題,就可以使用這種方式。如下:

const { data } = this.props;
try {
  data.forEach(d=>{});
  // 如果 data 不是數組就會報錯
} catch(err){
  console.error(err);
  // 這里可以做上報處理等操作
}

一些使用方式

十分不友好的處理方式

try...catch... 使用需要注意,try…catch… 后,錯誤會被攔截,如果不主動拋出錯誤,那么無法知道報錯位置。如下面的處理方式就是不好的。

function badHandler(fn) {
  try {
    return fn();
  } catch (err) { /**noop,不做任何處理**/ }
  return null;
}
badHandler();

這樣 fn 回調發送錯誤后,我們無法知道錯誤是在哪里發生的,因為已經被 try…catch 了,那么如何解決這個問題呢?

相對友好但糟糕的處理方式
function CustomError(...args){
  class InnerCustomError extends Error {
    name = "CustomError";
  }
  return new InnerCustomError(...args);
}
function uglyHandlerImproved(fn) {
  try {
    return fn();
  } catch (err) { 
    throw new CustomError(err.message);
  }
  return null;
}
badHandler();

現在,這個自定義的錯誤對象包含了原本錯誤的信息,因此變得更加有用。但是因為再度拋出來,依然是未處理的錯誤。

try…catch… 可以攔截異步錯誤嗎?

這個也要分場景,也看個人的理解方向,首先理解下面這句話:

try…catch 只會攔截當前執行環境的錯誤,try 塊中的異步已經脫離了當前的執行環境,所以 try…catch… 無效。

setTimeout 和 Promise 都無法通過 try…catch 捕獲到錯誤,指的是 try 包含異步(非當前執行環境),不是異步包含 try(當前執行環境)。異步無效和有效 try…catch 如下:

setTimeout

這個無效:

try {
  setTimeout(() => {
    data.forEach(d => {});
  });
} catch (err) {
  console.log('這里不會運行');
}

下面的 try…catch 才會有效:

setTimeout(() => {
  try {
    data.forEach(d => {});
  } catch (err) {
    console.log('這里會運行');
  }
});

Promise

這個無效:

try {
  new Promise(resolve => {
    data.forEach(d => {});
    resolve();
  });
} catch (err) {
  console.log('這里不會運行');
}

下面的 try…catch 才會有效:

new Promise(resolve => {
  try {
    data.forEach(d => {});
  } catch (err) {
    console.log('這里會運行');
  }
});

小結

不是所有場景都需要 try…catch… 的,如果所有需要的地方都 try…catch,那么代碼將變得臃腫,可讀性變差,開發效率變低。那么我需要統一獲取錯誤信息呢?有沒有更好的處理方式?當然有,后續會提到。

Promise 錯誤攔截

Promise.prototype.catch 可以達到 try…catch 一樣的效果,只要是在 Promise 相關的處理中報錯,都會被 catch 到。當然如果你在相關回調函數中 try…catch,然后做了靜默提示,那么也是 catch  不到的。

如下會被 catch 到:

new Promise(resolve => {
  data.forEach(v => {});
}).catch(err=>{/*這里會運行*/})

下面的不會被 catch 到:

new Promise(resolve => {
  try {
      data.forEach(v => {});
  }catch(err){}
}).catch(err=>{/*這里不會運行*/})

Promise 錯誤攔截,這里就不詳細說了,如果你看懂了 try…catch,這個也很好理解。

setTimeout 等其他異步錯誤攔截呢?

目前沒有相關的方式直接攔截 setTimeout 等其他異步操作。

如果要攔截 setTimeout 等異步錯誤,我們需要在異步回調代碼中處理,如:

setTimeout(() => {
  try {
    data.forEach(d => {});
  } catch (err) {
    console.log('這里會運行');
  }
});

這樣可以攔截到 setTimeout 回調發生的錯誤,但是如果是下面這樣 try…catch 是無效的:

try {
  setTimeout(() => {
    data.forEach(d => {});
  });
} catch (err) {
  console.log('這里不會運行');
}

如何獲取 JavaScript 錯誤信息?

你可以使用上面攔截錯誤信息的方式獲取到錯誤信息。但是呢,你要每個場景都要去攔截一遍嗎?首先我們不確定什么地方會發生錯誤,然后我們也不可能每個地方都去攔截錯誤。

不用擔心,JavaScript 也考慮到了這一點,提供了一些便捷的獲取方式(不是攔截,錯誤還是會終止程序的運行,除非主動攔截了)。

window.onerror 事件獲取錯誤信息

onerror 事件無論是異步還是非異步錯誤(除了 Promise 錯誤),onerror 都能捕獲到運行時錯誤。

需要注意一下幾點:

window.onerror 函數只有在返回 true 的時候,異常才不會向上拋出,否則即使是知道異常的發生控制臺還是會顯示 Uncaught Error: xxxxx。如果使用 addEventListener,event.preventDefault() 可以達到同樣的效果。

window.onerror 是無法捕獲到網絡異常的錯誤、<img/>或<script>資源加載失敗等錯誤。不過如果你使用了 fetch 等支持 promise 的方式,錯誤可以通過 unhandledrejection 方式拿到錯誤信息。

語法:

window.onerror

window.onerror = function(message, source, lineno, colno, error) { ... }

window.addEventListener('error')

window.addEventListener('error', function(event) { ... })

詳細看這里。

unhandledrejection 事件獲取 Promise 錯誤

unhandledrejection 存在兼容性問題,IE、Edge、火狐等目前都不支持。

用法如下:

window.addEventListener("unhandledrejection", event => {
  console.warn(`UNHANDLED PROMISE REJECTION: ${event.reason}`);
});

或者

window.onunhandledrejection = event => {
  console.warn(`UNHANDLED PROMISE REJECTION: ${event.reason}`);
};

詳細看這里。

如何處理錯誤信息?

錯誤對象 Error 包含如下的字段返回:

name

錯誤的類型,一般有 Error、TypeError、ReferenceError、RangeError、URIError 等,當然也可以是自定義的錯誤類型。

message

錯誤的詳細信息,可以是 JavaScript 自動拋出的錯誤信息,也可以是手動拋出的自定義信息。

stack

這個不是規范,存在兼容性。經測試,谷歌、火狐、Edge、safar 都支持此特性(都是在最新的版本下測試 2019-04-02),IE 不支持。

name 和 message 我們都不用做什么處理,主要是要針對 stack 做處理,一般我們需要把,這三個字段的信息提交到錯誤處理系統,針對性處理。

同時我們生成環境的代碼是被壓縮后的代碼,需要使用 sourceMap 進行映射還原代碼。

關于JavaScript中錯誤異常的案例就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

邹城市| 顺昌县| 大石桥市| 土默特右旗| 九江市| 和顺县| 铁力市| 黔西| 原阳县| 新绛县| 来凤县| 武乡县| 桑植县| 乐东| 临澧县| 宜君县| 满洲里市| 会东县| 墨竹工卡县| 曲阜市| 美姑县| 会泽县| 凤冈县| 永昌县| 班玛县| 区。| 彝良县| 北流市| 阿坝县| 海南省| 连州市| 龙游县| 伊吾县| 贵州省| 集安市| 恭城| 枣阳市| 闵行区| 临泽县| 广水市| 综艺|