溫馨提示×

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

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

JavaScript 錯(cuò)誤處理的解決過(guò)程是怎樣的

發(fā)布時(shí)間:2021-09-30 14:38:19 來(lái)源:億速云 閱讀:157 作者:柒染 欄目:web開發(fā)

本篇文章為大家展示了JavaScript 錯(cuò)誤處理的解決過(guò)程是怎樣的,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過(guò)這篇文章的詳細(xì)介紹希望你能有所收獲。

什么是編程中的錯(cuò)誤

我們的開發(fā)過(guò)程中并不總是一帆風(fēng)順。特別是在某些情況下,我們可能希望停止程序或在發(fā)生不良情況時(shí)通知用戶。

在類似這些情況下,我們可以自己寫個(gè)自定義的錯(cuò)誤來(lái)管理,或者直接讓引擎為我們?nèi)ザx這些錯(cuò)誤。有了錯(cuò)誤定義后,我們可以用消息通知用戶,或者停止執(zhí)行程序的運(yùn)行。

JavaScript 中的錯(cuò)誤是什么

JavaScript中的錯(cuò)誤是一個(gè)對(duì)象。要在 JS 創(chuàng)建一個(gè)錯(cuò)誤,可以使用 Error 對(duì)象,如下所示:

const err = new Error('霍霍,好像哪里出問(wèn)題了!')

也可以省略new關(guān)鍵字:

const err = Error('霍霍,好像哪里出問(wèn)題了!')

創(chuàng)建,錯(cuò)誤對(duì)象有三個(gè)屬性:

  • message:帶有錯(cuò)誤消息的字符串

  • name:錯(cuò)誤的類型

  • stack:函數(shù)執(zhí)行的堆棧跟蹤

例如,我們使用 TypeError 對(duì)象創(chuàng)建一個(gè)錯(cuò)誤,對(duì)應(yīng)的 message 是創(chuàng)建的傳入的字符號(hào),name 是 "TypeError"

const wrongType = TypeError("霍霍,好像哪里出問(wèn)題了!") wrongType.message // "霍霍,好像哪里出問(wèn)題了!" wrongType.name // "TypeError"

JavaScript中的許多類型的錯(cuò)誤

JavaScript 中有很多類型的錯(cuò)誤 ,如:

  • Error

  • EvalError

  • InternalError

  • RangeError

  • ReferenceError

  • SyntaxError

  • TypeError

  • URIError

記住,所有這些錯(cuò)誤類型都是實(shí)際的構(gòu)造函數(shù),意味著返回一個(gè)新的錯(cuò)誤對(duì)象。

在我們的代碼中,主要還是使用Error和TypeError這兩種最常見(jiàn)的類型來(lái)創(chuàng)建自己的錯(cuò)誤對(duì)象 。

大多數(shù)時(shí)候,大多數(shù)錯(cuò)誤將直接來(lái)自JavaScript引擎,例如InternalError或SyntaxError。

如果你重新賦值給 const 聲明的變量時(shí),就會(huì)引發(fā) TypeError 錯(cuò)誤。

const name = "前端小智" name = "王大冶" // // TypeError: Assignment to constant variable.

SyntaxError 錯(cuò)誤一般是關(guān)鍵字打錯(cuò)了,如下所示:

va x = '33'; // SyntaxError: Unexpected identifier

或者,當(dāng)在錯(cuò)誤的地方使關(guān)鍵字時(shí),例如await 和 async 的使用:

function wrong(){     await 99; }wrong();// SyntaxError: await is only valid in async function

另一個(gè)TypeError的例子是,在頁(yè)面操作不存在的 DOM 元素。

Uncaught TypeError: button is null

除了這些內(nèi)置錯(cuò)誤外,在瀏覽器中還有:

  • DOMException

  • DOMError,現(xiàn)在已經(jīng)廢棄,不再使用了。

DOMException是與 Web API 相關(guān)的一系列錯(cuò)誤。當(dāng)我們?cè)跒g覽器中執(zhí)行愚蠢的操作時(shí),它們會(huì)被拋出,例如:

document.body.appendChild(document.cloneNode(true));

結(jié)果:

Uncaught DOMException: Node.appendChild: May not add a Document as a child

什么是異常?

大多數(shù)開發(fā)人員認(rèn)為錯(cuò)誤和異常是一回事。實(shí)際上,錯(cuò)誤對(duì)象只有在拋出時(shí)才會(huì)變成異常。

要在JavaScript中引發(fā)異常,我們使用throw 關(guān)鍵字把錯(cuò)誤拋出去:

const wrongType = TypeError("霍霍,好像哪里出問(wèn)題了!") throw wrongType;

簡(jiǎn)寫形式:

throw TypeError("霍霍,好像哪里出問(wèn)題了!")

或者

throw new TypeError("霍霍,好像哪里出問(wèn)題了!")

在函數(shù)體或者條件之外拋出異步的可能性不大,考慮下面的例子:

function toUppercase(string) {   if (typeof string !== "string") {     throw TypeError("霍霍,好像哪里出問(wèn)題了!");   }  return string.toUpperCase(); }

這里我們檢查函數(shù)參數(shù)是否為字符串。如果不是,我們拋出一個(gè)異常。從技術(shù)上講,JavaScript中可以拋出任何東西,而不僅僅是錯(cuò)誤對(duì)象

throw Symbol(); throw 33; throw "Error!"; throw null;

但是,最好避免這些事情:始終拋出正確的錯(cuò)誤對(duì)象,而不是一些基本類型。

這樣有助于在代碼中,錯(cuò)誤處理的一致性。其他成員可以期望在錯(cuò)誤對(duì)象上訪問(wèn)error.message或error.stack 來(lái)知道錯(cuò)誤的源頭。

當(dāng)我們拋出異常時(shí)會(huì)發(fā)生什么?

異常就像一個(gè)上升的電梯:一旦你拋出一個(gè),它就會(huì)在程序堆棧中冒泡,除非它在某個(gè)地方被捕獲。

考慮以下代碼:

function toUppercase(string) {   if (typeof string !== "string") {     throw TypeError("參數(shù)類型需要是 string 的");   }  return string.toUpperCase(); }toUppercase(4);

運(yùn)行代碼會(huì)在控制臺(tái)看到:

Uncaught TypeError: Wrong type given, expected a string     toUppercase http://localhost:5000/index.js:3     <anonymous> http://localhost:5000/index.js:9

可以看到發(fā)生錯(cuò)誤的確切行。

這個(gè)報(bào)告是一個(gè)堆棧跟蹤,它有助于跟蹤代碼中的問(wèn)題。堆棧跟蹤從下至上:

toUppercase http://localhost:5000/index.js:3    <anonymous> http://localhost:5000/index.js:9

除了在瀏覽器的控制臺(tái)中看到此堆棧跟蹤外,還可以通過(guò)錯(cuò)誤對(duì)象的stack屬性進(jìn)行查看。

如果異常未被捕獲,也就是說(shuō),程序員不采取任何措施來(lái)捕獲它,程序?qū)⒈罎ⅰ?/p>

何時(shí)何地捕獲代碼中的異常取決于特定的用例。

例如,我們可能想在堆棧中傳遞一個(gè)異常,以使程序完全崩潰。這種情況發(fā)生在, 讓錯(cuò)誤停止程序比處理無(wú)效數(shù)據(jù)來(lái)得更安全。

接下來(lái),我們來(lái)看看 JavaScript 同步和異步中的錯(cuò)誤和異常處理。

同步中的錯(cuò)誤處理

同步代碼在大多數(shù)情況下都很簡(jiǎn)單,因此它的錯(cuò)誤處理也很簡(jiǎn)單。

常規(guī)函數(shù)的錯(cuò)誤處理

同步代碼的執(zhí)行順序與寫入順序相同。我們?cè)倏匆幌虑懊娴睦樱?/p>

function toUppercase(string) {   if (typeof string !== "string") {     throw TypeError("參數(shù)類型需要是 string 的");   }  return string.toUpperCase(); }toUppercase(4);

在這里,引擎調(diào)用并執(zhí)行toUppercase。所有這些都是同步發(fā)生的。要捕獲同步函數(shù)引發(fā)的異常,我們可以使用try/catch/finally:

try {   toUppercase(4); } catch (error) {   console.error(error.message); } finally { }

try/catch/finally是一個(gè)同步結(jié)構(gòu),但它也可以捕獲異步出現(xiàn)的異常。

使用 generator 函數(shù)來(lái)處理錯(cuò)誤

JavaScript中的生成器函數(shù)是一種特殊的函數(shù)。除了在其內(nèi)部作用域和使用者之間提供雙向通信通道之外,還可以隨意暫停和恢復(fù)。

要?jiǎng)?chuàng)建一個(gè)生成器函數(shù),我們?cè)趂unction關(guān)鍵字后面放一個(gè)*:

function* generate() {   // }

在函數(shù)內(nèi)可以使用yield返回值:

function* generate() {   yield 33;   yield 99; }

生成器函數(shù)的返回值是一個(gè)迭代器對(duì)象(iterator object)。要從生成器中提取值,我們可以使用兩種方法:

  • 使用 next() 方法

  • 通過(guò) for...of 遍歷

如下所示,要想在生成器中獲取值,我們可以這樣做:

function* generate() {   yield 33;   yield 99; }const go = generate(); const firstStep = go.next().value; // 33 const secondStep = go.next().value; // 99

成器也可以采用其他方法工作:它們可以接收調(diào)用者返回的值和異常。

除了next()之外,從生成器返回的迭代器對(duì)象還具有throw()方法。使用這種方法,我們可以通過(guò)向生成器中注入一個(gè)異常來(lái)停止程序:

function* generate() {   yield 33;   yield 99; }const go = generate(); const firstStep = go.next().value; // 33 go.throw(Error("我要結(jié)束你!")); const secondStep = go.next().value; // 這里會(huì)拋出異常

要獲取此錯(cuò)誤,可以在生成器函數(shù)中使用 try/catch/finally:

function* generate() {   try {     yield 33;     yield 99;   } catch (error) {     console.error(error.message);   }}

下面這個(gè)事例是使用 for...of 來(lái)獲取 生成器函數(shù)中的值:

function* generate() {   yield 33;   yield 99;     throw Error("我要結(jié)束你!") }try {   for (const value of generate()) {     console.log(value)   }} catch (error) {   console.log(error.message) }/* 輸出:   33   99   我要結(jié)束你! */

異步中的錯(cuò)誤處理

JavaScript本質(zhì)上是同步的,是一種單線程語(yǔ)言。

諸如瀏覽器引擎之類的宿主環(huán)境使用許多Web API, 增強(qiáng)了 JS 以與外部系統(tǒng)進(jìn)行交互并處理與 I/O 綁定的操作。

瀏覽器中異步操作有:定時(shí)器相關(guān)的函數(shù)、事件和 Promise。

異步中的錯(cuò)誤處理不同于同步的錯(cuò)誤處理。我們來(lái)看一些例子。

定時(shí)器的錯(cuò)誤處理

考慮下面的代碼片段:

function failAfterOneSecond() {   setTimeout(() => {     throw Error("Something went wrong!");   }, 1000); }

這個(gè)函數(shù)大約在1秒后拋出異常,處理這個(gè)異常的正確方法是什么?

下面的方法不起作用:

function failAfterOneSecond() {   setTimeout(() => {     throw Error("Something went wrong!");   }, 1000); }try {   failAfterOneSecond();} catch (error) {   console.error(error.message); }

我們知道 try/catch 是同步,而 setTimeout 是異步的。當(dāng)執(zhí)行到 setTimeout回調(diào)時(shí),try/catch  早已跑完了,所以異常就無(wú)法捕獲到。

它們?cè)趦蓜?wù)不同的軌道上:

Track A: --> try/catch Track B: --> setTimeout --> callback --> throw

如果能讓程序跑下去,把 try/catch 移動(dòng)到 setTimeout 里面。但這種做法意義不大,后面我們會(huì)使用 Promise  來(lái)解決這類的問(wèn)題。

事件中錯(cuò)誤處理

DOM  的事件操作(監(jiān)聽(tīng)和觸發(fā)),都定義在EventTarget接口。Element節(jié)點(diǎn)、document節(jié)點(diǎn)和window對(duì)象,都部署了這個(gè)接口。此外,XMLHttpRequest、AudioNode、AudioContext等瀏覽器內(nèi)置對(duì)象,也部署了這個(gè)接口。該接口就是三個(gè)方法,addEventListener和removeEventListener用于綁定和移除監(jiān)聽(tīng)函數(shù),dispatchEvent用于觸發(fā)事件。

DOM 事件的錯(cuò)誤處理機(jī)制遵循任何異步Web API的相同方案。

考慮下面示例:

const button = document.querySelector("button"); button.addEventListener("click", function() {   throw Error("Can't touch this button!"); });

在這里,單擊按鈕后立即引發(fā)異常。我們?nèi)绾巫プ∷?下面這種方式?jīng)]啥作用,也不會(huì)阻止程序崩潰:

const button = document.querySelector("button"); try {   button.addEventListener("click", function() {     throw Error("Can't touch this button!");   });} catch (error) {   console.error(error.message); }

與 setTimeout 一樣,addEventListener 也是異步執(zhí)行的。

Track A: --> try/catch Track B: --> addEventListener --> callback --> throw

如果能讓程序跑下去,把 try/catch 移動(dòng)到 addEventListener 里面。但這種做法意義不大,后面我們會(huì)使用 Promise  來(lái)解決這類的問(wèn)題。

onerror 怎么樣

HTML元素具有許多事件處理程序,例如onclick,onmouseenter,onchange等,當(dāng)然還有 onerror。

當(dāng) img 標(biāo)簽或 script 標(biāo)簽遇到不存在的資源時(shí),onerror事件處理程序都會(huì)觸發(fā)。

考慮下面示例:

... <body>   <img src="nowhere-to-be-found.png" alt="So empty!"> </body> ...

當(dāng)文件不存在時(shí),控制臺(tái)就會(huì)報(bào)如下的錯(cuò)誤:

GET http://localhost:5000/nowhere-to-be-found.png [HTTP/1.1 404 Not Found 3ms]

在 JS 中,我們可以通過(guò) onerror 來(lái)捕獲這個(gè)錯(cuò)誤:

const image = document.querySelector("img"); image.onerror = function(event) {   console.log(event); };

更好的方式:

const image = document.querySelector("img"); image.addEventListener("error", function(event) {   console.log(event); });

這種方式對(duì)于一些請(qǐng)求資源丟失的情況很有用,但 onerror 與 throw 與 try/cathc 無(wú)關(guān)。

上述內(nèi)容就是JavaScript 錯(cuò)誤處理的解決過(guò)程是怎樣的,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI