Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 亚洲国产网站,国产超a动作大片,亚洲一区二区综合

          整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          如何解決HTML頁(yè)面白屏問(wèn)題

          網(wǎng)頁(yè)開(kāi)發(fā)過(guò)程中,我們有時(shí)會(huì)遇到HTML頁(yè)面白屏的問(wèn)題,即打開(kāi)網(wǎng)頁(yè)時(shí)頁(yè)面顯示空白,沒(méi)有任何內(nèi)容。這不僅令用戶困惑,也使開(kāi)發(fā)者頭疼不已。本文將分享一些常見(jiàn)的HTML頁(yè)面白屏問(wèn)題解決方法,幫助你快速解決這個(gè)問(wèn)題,讓你的網(wǎng)頁(yè)煥然一新!

          第一步:檢查HTML代碼

          首先,我們需要檢查HTML代碼是否正確。常見(jiàn)的錯(cuò)誤包括標(biāo)簽未閉合、標(biāo)簽嵌套錯(cuò)誤等。這些錯(cuò)誤可能會(huì)導(dǎo)致頁(yè)面無(wú)法正常顯示。因此,仔細(xì)檢查HTML代碼,確保沒(méi)有語(yǔ)法錯(cuò)誤是解決白屏問(wèn)題的第一步。

          第二步:檢查CSS文件

          HTML頁(yè)面的樣式通常由CSS文件控制。如果CSS文件中存在錯(cuò)誤或者無(wú)法正常加載,可能會(huì)導(dǎo)致頁(yè)面白屏。我們可以通過(guò)以下步驟檢查CSS文件是否存在問(wèn)題:

          1、檢查CSS文件路徑是否正確:確保CSS文件的路徑正確,并且文件存在于指定的位置。可以通過(guò)瀏覽器開(kāi)發(fā)者工具查看網(wǎng)絡(luò)面板,檢查CSS文件是否被成功加載。

          2、檢查CSS文件語(yǔ)法錯(cuò)誤:使用CSS驗(yàn)證工具,如W3C CSS驗(yàn)證服務(wù),檢查CSS文件是否存在語(yǔ)法錯(cuò)誤。如果存在錯(cuò)誤,及時(shí)修復(fù)。

          3、檢查CSS選擇器和樣式規(guī)則:檢查CSS文件中的選擇器和樣式規(guī)則是否正確。可能存在選擇器與HTML元素不匹配或樣式規(guī)則沖突的情況。可以通過(guò)逐個(gè)注釋掉樣式規(guī)則,逐步排查問(wèn)題。

          第三步:檢查JavaScript代碼

          JavaScript代碼也可能導(dǎo)致頁(yè)面白屏。以下是檢查JavaScript代碼的步驟:

          1、檢查JS文件路徑是否正確:與CSS文件類似,確保JS文件的路徑正確,并且文件存在于指定的位置。通過(guò)瀏覽器開(kāi)發(fā)者工具查看控制臺(tái)面板,檢查是否有JS文件加載錯(cuò)誤的提示信息。

          2、檢查JS代碼語(yǔ)法錯(cuò)誤:使用JS語(yǔ)法檢查工具,檢查JS代碼是否存在語(yǔ)法錯(cuò)誤。如果有錯(cuò)誤,及時(shí)修復(fù)。

          3、檢查JS代碼邏輯錯(cuò)誤:檢查JS代碼中的邏輯是否正確。可能存在變量未定義、函數(shù)未調(diào)用或者邏輯錯(cuò)誤等問(wèn)題。可以通過(guò)調(diào)試工具,如瀏覽器開(kāi)發(fā)者工具中的調(diào)試器,逐步排查問(wèn)題。

          第四步:排查網(wǎng)絡(luò)請(qǐng)求問(wèn)題

          如果前面的步驟都沒(méi)有發(fā)現(xiàn)問(wèn)題,那么可能是網(wǎng)絡(luò)請(qǐng)求出現(xiàn)了問(wèn)題。以下是一些排查網(wǎng)絡(luò)請(qǐng)求問(wèn)題的方法:

          1、檢查網(wǎng)絡(luò)連接:確保你的設(shè)備已連接到互聯(lián)網(wǎng),并且網(wǎng)絡(luò)連接穩(wěn)定。

          2、檢查資源加載狀態(tài):通過(guò)瀏覽器開(kāi)發(fā)者工具的網(wǎng)絡(luò)面板,檢查頁(yè)面中的資源加載狀態(tài)。可能存在資源加載失敗或者超時(shí)的情況,導(dǎo)致頁(yè)面白屏。

          3、檢查服務(wù)器配置:如果你使用了服務(wù)器端腳本語(yǔ)言,如PHP,檢查服務(wù)器配置是否正確。可能存在服務(wù)器配置問(wèn)題導(dǎo)致頁(yè)面無(wú)法正確渲染。

          第五步:優(yōu)化頁(yè)面性能

          如果以上方法都沒(méi)有解決問(wèn)題,那么可能是頁(yè)面性能問(wèn)題導(dǎo)致白屏。以下是一些優(yōu)化頁(yè)面性能的方法:

          1、壓縮和合并文件:將CSS和JS文件進(jìn)行壓縮和合并,減少文件的大小和數(shù)量,提高頁(yè)面加載速度。

          2、使用緩存:利用瀏覽器緩存機(jī)制,將靜態(tài)資源進(jìn)行緩存,減少服務(wù)器的請(qǐng)求次數(shù),提高頁(yè)面加載速度。

          3、異步加載資源:使用異步加載技術(shù),如異步加載JS文件或使用延遲加載,減少頁(yè)面加載時(shí)間。

          4、減少HTTP請(qǐng)求:減少頁(yè)面中的HTTP請(qǐng)求次數(shù)等。

          結(jié)語(yǔ):

          通過(guò)以上五個(gè)步驟,我們可以逐步排查HTML頁(yè)面白屏問(wèn)題,并解決它們。不同的問(wèn)題可能需要不同的解決方法,因此需要耐心和細(xì)心地分析和排查。在開(kāi)發(fā)過(guò)程中,我們也要時(shí)刻關(guān)注頁(yè)面性能,優(yōu)化頁(yè)面加載速度,提高用戶體驗(yàn)。

          家好,我是 Echa。

          本文將帶你了解 JavaScript 中常見(jiàn)的錯(cuò)誤類型,處理同步和異步 JavaScript/Node.js 代碼中錯(cuò)誤和異常的方式,以及錯(cuò)誤處理最佳實(shí)踐!

          1. 錯(cuò)誤概述

          JavaScript 中的錯(cuò)誤是一個(gè)對(duì)象,在發(fā)生錯(cuò)誤時(shí)會(huì)拋出該對(duì)象以停止程序。在 JavaScript 中,可以通過(guò)構(gòu)造函數(shù)來(lái)創(chuàng)建一個(gè)新的通用錯(cuò)誤:

          const err = new Error("Error");
          

          當(dāng)然,也可以省略 new 關(guān)鍵字:

          const err = Error("Error");
          

          Error 對(duì)象有三個(gè)屬性:

          • message:帶有錯(cuò)誤消息的字符串;
          • name: 錯(cuò)誤的類型;
          • stack:函數(shù)執(zhí)行的堆棧跟蹤。

          例如,創(chuàng)建一個(gè) TypeError 對(duì)象,該消息將攜帶實(shí)際的錯(cuò)誤字符串,其 name 將是“TypeError”:

          const wrongType = TypeError("Expected number");
          
          wrongType.message; // 'Expected number'
          wrongType.name;    // 'TypeError'
          

          堆棧跟蹤是發(fā)生異常或警告等事件時(shí)程序所處的方法調(diào)用列表:

          它首先會(huì)打印錯(cuò)誤名稱和消息,然后是被調(diào)用的方法列表。每個(gè)方法調(diào)用都說(shuō)明其源代碼的位置和調(diào)用它的行。可以使用此數(shù)據(jù)來(lái)瀏覽代碼庫(kù)并確定導(dǎo)致錯(cuò)誤的代碼段。此方法列表以堆疊的方式排列。它顯示了異常首先被拋出的位置以及它如何通過(guò)堆棧方法調(diào)用傳播。為異常實(shí)施捕獲不會(huì)讓它通過(guò)堆棧向上傳播并使程序崩潰。

          對(duì)于 Error 對(duì)象,F(xiàn)irefox 還實(shí)現(xiàn)了一些非標(biāo)準(zhǔn)屬性:

          • columnNumber:錯(cuò)誤所在行的列號(hào);
          • filename:發(fā)生錯(cuò)誤的文件
          • lineNumber:發(fā)生錯(cuò)誤的行號(hào)

          2. 錯(cuò)誤類型

          JavaScript 中有一系列預(yù)定義的錯(cuò)誤類型。只要使用者沒(méi)有明確處理應(yīng)用程序中的錯(cuò)誤,它們就會(huì)由 JavaScript 運(yùn)行時(shí)自動(dòng)選擇和定義。

          JavaScript中的錯(cuò)誤類型包括:

          • EvalError
          • InternalError
          • RangeError
          • ReferenceError
          • SyntaxError
          • TypeError
          • URIError

          這些錯(cuò)誤類型都是實(shí)際的構(gòu)造函數(shù),旨在返回一個(gè)新的錯(cuò)誤對(duì)象。最常見(jiàn)的就是 TypeError。大多數(shù)時(shí)候,大部分錯(cuò)誤將直接來(lái)自 JavaScript 引擎,例如 InternalError 或 SyntaxError。

          JavaScript 提供了 instanceof 運(yùn)算符可以用于區(qū)分異常類型:

          try {
            If (typeof x !== ‘number’) {
                 throw new TypeError(‘x 應(yīng)是數(shù)字’);
            } else if (x <= 0) {
                 throw new RangeError('x 應(yīng)大于 0');
            } else {
                 // ...
            }
          } catch (err) {
              if (err instanceof TypeError) {
                // 處理 TypeError 錯(cuò)誤
              } else if (err instanceof RangeError) {
                // 處理 RangeError 錯(cuò)誤
            } else {
                // 處理其他類型錯(cuò)誤
            }
          }
          

          下面來(lái)了解 JavaScript 中最常見(jiàn)的錯(cuò)誤類型,并了解它們發(fā)生的時(shí)間和原因。

          (1)SyntaxError

          SyntaxError 表示語(yǔ)法錯(cuò)誤。這些錯(cuò)誤是最容易修復(fù)的錯(cuò)誤之一,因?yàn)樗鼈儽砻鞔a語(yǔ)法中存在錯(cuò)誤。由于 JavaScript 是一種解釋而非編譯的腳本語(yǔ)言,因此當(dāng)應(yīng)用程序執(zhí)行包含錯(cuò)誤的腳本時(shí)會(huì)拋出這些錯(cuò)誤。在編譯語(yǔ)言的情況下,此類錯(cuò)誤在編譯期間被識(shí)別。因此,在修復(fù)這些問(wèn)題之前,不會(huì)創(chuàng)建應(yīng)用程序二進(jìn)制文件。

          SyntaxError 發(fā)生的一些常見(jiàn)原因是:

          • 缺少引號(hào)
          • 缺少右括號(hào)
          • 大括號(hào)或其他字符對(duì)齊不當(dāng)

          (2)TypeError

          TypeError 是 JavaScript 應(yīng)用程序中最常見(jiàn)的錯(cuò)誤之一,當(dāng)某些值不是特定的預(yù)期類型時(shí),就會(huì)產(chǎn)生此錯(cuò)誤。

          TypeError 發(fā)生的一些常見(jiàn)原因是:

          • 調(diào)用不是方法的對(duì)象。
          • 試圖訪問(wèn) null 或未定義對(duì)象的屬性
          • 將字符串視為數(shù)字,反之亦然

          (3)ReferenceError

          ReferenceError 表示引用錯(cuò)誤。當(dāng)代碼中的變量引用有問(wèn)題時(shí),會(huì)發(fā)生 ReferenceError。可能忘記在使用變量之前為其定義一個(gè)值,或者可能試圖在代碼中使用一個(gè)不可訪問(wèn)的變量。在任何情況下,通過(guò)堆棧跟蹤都可以提供充足的信息來(lái)查找和修復(fù)有問(wèn)題的變量引用。

          ReferenceErrors 發(fā)生的一些常見(jiàn)原因如下:

          • 在變量名中輸入錯(cuò)誤。
          • 試圖訪問(wèn)其作用域之外的塊作用域變量。
          • 在加載之前從外部庫(kù)引用全局變量。

          (4)RangeError

          RangeError 表示范圍錯(cuò)誤。當(dāng)變量設(shè)置的值超出其合法值范圍時(shí),將拋出 RangeError。它通常發(fā)生在將值作為參數(shù)傳遞給函數(shù)時(shí),并且給定值不在函數(shù)參數(shù)的范圍內(nèi)。當(dāng)使用記錄不完整的第三方庫(kù)時(shí),有時(shí)修復(fù)起來(lái)會(huì)很棘手,因?yàn)樾枰绤?shù)的可能值范圍才能傳遞正確的值。

          RangeError 發(fā)生的一些常見(jiàn)場(chǎng)景如下:

          • 試圖通過(guò) Array 構(gòu)造函數(shù)創(chuàng)建非法長(zhǎng)度的數(shù)組。
          • 將錯(cuò)誤的值傳遞給數(shù)字方法,例如 toExponential()toPrecision()toFixed()等。
          • 將非法值傳遞給字符串函數(shù),例如 normalize()

          (5)URIError

          URIError 表示 URI錯(cuò)誤。當(dāng) URI 的編碼和解碼出現(xiàn)問(wèn)題時(shí),會(huì)拋出 URIError。JavaScript 中的 URI 操作函數(shù)包括:decodeURIdecodeURIComponent 等。如果使用了錯(cuò)誤的參數(shù)(無(wú)效字符),就會(huì)拋出 URIError。

          (6)EvalError

          EvalError 表示 Eval 錯(cuò)誤。當(dāng) eval() 函數(shù)調(diào)用發(fā)生錯(cuò)誤時(shí),會(huì)拋出 EvalError。不過(guò),當(dāng)前的 JavaScript 引擎或 ECMAScript 規(guī)范不再拋出此錯(cuò)誤。但是,為了向后兼容,它仍然是存在的。

          如果使用的是舊版本的 JavaScript,可能會(huì)遇到此錯(cuò)誤。在任何情況下,最好調(diào)查在eval()函數(shù)調(diào)用中執(zhí)行的代碼是否有任何異常。

          (7)InternalError

          InternalError 表示內(nèi)部錯(cuò)誤。在 JavaScript 運(yùn)行時(shí)引擎發(fā)生異常時(shí)使用。它表示代碼可能存在問(wèn)題也可能不存在問(wèn)題。

          InternalError 通常只發(fā)生在兩種情況下:

          • 當(dāng) JavaScript 運(yùn)行時(shí)的補(bǔ)丁或更新帶有引發(fā)異常的錯(cuò)誤時(shí)(這種情況很少發(fā)生);
          • 當(dāng)代碼包含對(duì)于 JavaScript 引擎而言太大的實(shí)體時(shí)(例如,數(shù)組初始值設(shè)定項(xiàng)太大、遞歸太多)。

          解決此錯(cuò)誤最合適的方法就是通過(guò)錯(cuò)誤消息確定原因,并在可能的情況下重構(gòu)應(yīng)用邏輯,以消除 JavaScript 引擎上工作負(fù)載的突然激增。

          注意: 現(xiàn)代 JavaScript 中不會(huì)拋出 EvalError 和 InternalError。

          (8)創(chuàng)建自定義錯(cuò)誤類型

          雖然 JavaScript 提供了足夠的錯(cuò)誤類型類列表來(lái)涵蓋大多數(shù)情況,但如果這些錯(cuò)誤類型不能滿足要求,還可以創(chuàng)建新的錯(cuò)誤類型。這種靈活性的基礎(chǔ)在于 JavaScript 允許使用 throw 命令拋出任何內(nèi)容。

          可以通過(guò)擴(kuò)展 Error 類以創(chuàng)建自定義錯(cuò)誤類:

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

          可以通過(guò)以下方式使用它:

          throw ValidationError("未找到該屬性: name")
          

          可以使用 instanceof 關(guān)鍵字識(shí)別它:

          try {
              validateForm() // 拋出 ValidationError 的代碼
          } catch (e) {
              if (e instanceof ValidationError) {
                
              }
              else {
                
              }
          }
          

          3. 拋出錯(cuò)誤

          很多人認(rèn)為錯(cuò)誤和異常是一回事。實(shí)際上,Error 對(duì)象只有在被拋出時(shí)才會(huì)成為異常

          在 JavaScript 中拋出異常,可以使用 throw 來(lái)拋出 Error 對(duì)象:

          throw TypeError("Expected number");
          

          或者:

          throw new TypeError("Expected number");
          

          來(lái)看一個(gè)簡(jiǎn)單的例子:

          function toUppercase(string) {
            if (typeof string !== "string") {
              throw TypeError("Expected string");
            }
          
            return string.toUpperCase();
          }
          

          在這里,我們檢查函數(shù)參數(shù)是否為字符串。如果不是,就拋出異常。

          從技術(shù)上講,我們可以在 JavaScript 中拋出任何東西,而不僅僅是 Error 對(duì)象:

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

          但是,最好避免這樣做:要拋出正確的 Error 對(duì)象,而不是原語(yǔ)

          4. 拋出異常時(shí)會(huì)發(fā)生什么?

          異常一旦拋出,就會(huì)在程序堆棧中冒泡,除非在某個(gè)地方被捕獲。

          來(lái)看下面的例子:

          function toUppercase(string) {
            if (typeof string !== "string") {
              throw TypeError("Expected string");
            }
          
            return string.toUpperCase();
          }
          
          toUppercase(4);
          

          在瀏覽器或 Node.js 中運(yùn)行此代碼,程序?qū)⑼V共伋鲥e(cuò)誤:

          這里還顯示了發(fā)生錯(cuò)誤的確切行。這個(gè)錯(cuò)誤就是一個(gè)堆棧跟蹤,有助于跟蹤代碼中的問(wèn)題。堆棧跟蹤從下到上:

          at toUppercase (<anonymous>:3:11)
          at <anonymous>:9:1
          

          toUppercase 函數(shù)在第 9 行調(diào)用,在第 3 行拋出錯(cuò)誤。除了在瀏覽器的控制臺(tái)中查看此堆棧跟蹤之外,還可以在 Error 對(duì)象的 stack 屬性上訪問(wèn)它。

          介紹完這些關(guān)于錯(cuò)誤的基礎(chǔ)知識(shí)之后,下面來(lái)看看同步和異步 JavaScript 代碼中的錯(cuò)誤和異常處理。

          5. 同步錯(cuò)誤處理

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

          同步代碼會(huì)按照代碼編寫(xiě)順序執(zhí)行。讓我們?cè)倏纯辞懊娴睦樱?/span>

          function toUppercase(string) {
            if (typeof string !== "string") {
              throw TypeError("Expected 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 會(huì)處理正常的路徑,或者可能進(jìn)行的函數(shù)調(diào)用。catch 就會(huì)捕獲實(shí)際的異常,它接收 Error 對(duì)象。而不管函數(shù)的結(jié)果如何,finally 語(yǔ)句都會(huì)運(yùn)行:無(wú)論它失敗還是成功,finally 中的代碼都會(huì)運(yùn)行。

          (2)生成器函數(shù)的錯(cuò)誤處理

          JavaScript 中的生成器函數(shù)是一種特殊類型的函數(shù)。它可以隨意暫停和恢復(fù),除了在其內(nèi)部范圍和消費(fèi)者之間提供雙向通信通道。為了創(chuàng)建一個(gè)生成器函數(shù),需要在 function 關(guān)鍵字后面加上一個(gè) *

          function* generate() {
          //
          }
          

          只要進(jìn)入函數(shù),就可以使用 yield 來(lái)返回值:

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

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

          • 在迭代器對(duì)象上調(diào)用 next()
          • 使用 for...of 進(jìn)行迭代

          以上面的代碼為例,要從生成器中獲取值,可以這樣做:

          function* generate() {
            yield 33;
            yield 99;
          }
          
          const go = generate();
          

          當(dāng)我們調(diào)用生成器函數(shù)時(shí),這里的 go 就是生成的迭代器對(duì)象。接下來(lái),就可以調(diào)用 go.next() 來(lái)繼續(xù)執(zhí)行:

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

          生成器也可以接受來(lái)自調(diào)用者的值和異常。除了 next(),從生成器返回的迭代器對(duì)象還有一個(gè) throw() 方法。使用這種方法,就可以通過(guò)向生成器中注入異常來(lái)停止程序:

          function* generate() {
            yield 33;
            yield 99;
          }
          
          const go = generate();
          
          const firstStep = go.next().value; // 33
          
          go.throw(Error("Tired of iterating!"));
          
          const secondStep = go.next().value; // never reached
          

          要捕獲此類錯(cuò)誤,可以使用 try/catch 將代碼包裝在生成器中:

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

          生成器函數(shù)也可以向外部拋出異常。 捕獲這些異常的機(jī)制與捕獲同步異常的機(jī)制相同:try/catch/finally。

          下面是使用 for...of 從外部使用的生成器函數(shù)的示例:

          function* generate() {
            yield 33;
            yield 99;
            throw Error("Tired of iterating!");
          }
          
          try {
            for (const value of generate()) {
              console.log(value);
            }
          } catch (error) {
            console.error(error.message);
          }
          

          輸出結(jié)果如下:

          這里,try 塊中包含正常的迭代。如果發(fā)生任何異常,就會(huì)用 catch 捕獲它。

          6. 異步錯(cuò)誤處理

          瀏覽器中的異步包括定時(shí)器、事件、Promise 等。異步世界中的錯(cuò)誤處理與同步世界中的處理不同。下面來(lái)看一些例子。

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

          上面我們介紹了如何使用 try/catch/finally 來(lái)處理錯(cuò)誤,那異步中可以使用這些來(lái)處理錯(cuò)誤嗎?先來(lái)看一個(gè)例子:

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

          此函數(shù)在大約 1 秒后會(huì)拋出錯(cuò)誤。那處理此異常的正確方法是什么?以下代碼是無(wú)效的:

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

          我們知道,try/catch是同步的,所以沒(méi)辦法這樣來(lái)處理異步中的錯(cuò)誤。當(dāng)傳遞給 setTimeout的回調(diào)運(yùn)行時(shí),try/catch 早已執(zhí)行完畢。程序?qū)?huì)崩潰,因?yàn)槲茨懿东@異常。它們是在兩條路徑上執(zhí)行的:

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

          (2)事件的錯(cuò)誤處理

          我們可以監(jiān)聽(tīng)頁(yè)面中任何 HTML 元素的事件,DOM 事件的錯(cuò)誤處理機(jī)制遵循與任何異步 Web API 相同的方案。

          來(lái)看下面的例子:

          const button = document.querySelector("button");
          
          button.addEventListener("click", function() {
            throw Error("error");
          });
          

          這里,在單擊按鈕后立即拋出了異常,我們?cè)撊绾尾东@這個(gè)異常呢?這樣寫(xiě)是不起作用的,也不會(huì)阻止程序崩潰:

          const button = document.querySelector("button");
          
          try {
            button.addEventListener("click", function() {
              throw Error("error");
            });
          } catch (error) {
            console.error(error.message);
          }
          

          與前面的 setTimeout 例子一樣,任何傳遞給 addEventListener 的回調(diào)都是異步執(zhí)行的:

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

          如果不想讓程序崩潰,為了正確處理錯(cuò)誤,就必須將 try/catch 放到 addEventListener 的回調(diào)中。不過(guò)這樣做并不是最佳的處理方式,與 setTimeout 一樣,異步代碼路徑拋出的異常無(wú)法從外部捕獲,并且會(huì)使程序崩潰。

          下面會(huì)介紹 Promises 和 async/await 是如何簡(jiǎn)化異步代碼的錯(cuò)誤處理的。

          (3)onerror

          HTML 元素有許多事件處理程序,例如 onclickonmouseenteronchange 等。除此之外,還有 onerror,每當(dāng) <img> 標(biāo)簽或 <script> 等 HTML 元素命中不存在的資源時(shí),onerror 事件處理程序就會(huì)觸發(fā)。

          來(lái)看下面的例子:

          <body>
            <img src="nowhere-to-be-found.png">
          </body>
          

          當(dāng)訪問(wèn)的資源缺失時(shí),瀏覽器的控制臺(tái)就會(huì)報(bào)錯(cuò):

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

          在 JavaScript 中,可以使用適當(dāng)?shù)氖录幚沓绦颉安东@”此錯(cuò)誤:

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

          或者使用 addEventListener 來(lái)監(jiān)聽(tīng) error 事件,當(dāng)發(fā)生錯(cuò)誤時(shí)進(jìn)行處理:

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

          此模式對(duì)于加載備用資源以代替丟失的圖像或腳本很有用。不過(guò)需要記住:onerror 與 throw 或 try/catch 是無(wú)關(guān)的。

          (4)Promise 的錯(cuò)誤處理

          下面來(lái)通過(guò)最上面的 toUppercase 例子看看 Promise 是如何處理錯(cuò)誤的:

          function toUppercase(string) {
            if (typeof string !== "string") {
              throw TypeError("Expected string");
            }
          
            return string.toUpperCase();
          }
          
          toUppercase(4);
          

          對(duì)上面的代碼進(jìn)行修改,不返回簡(jiǎn)單的字符串或異常,而是分別使用 Promise.rejectPromise.resolve 來(lái)處理錯(cuò)誤和成功:

          function toUppercase(string) {
            if (typeof string !== "string") {
              return Promise.reject(TypeError("Expected string"));
            }
          
            const result = string.toUpperCase();
          
            return Promise.resolve(result);
          }
          

          從技術(shù)上講,這段代碼中沒(méi)有任何異步的內(nèi)容,但它可以很好地說(shuō)明 Promise 的錯(cuò)誤處理機(jī)制。

          現(xiàn)在我們就可以在 then 中使用結(jié)果,并使用 catch 來(lái)處理被拒絕的 Promise:

          toUppercase(99)
            .then(result => result)
            .catch(error => console.error(error.message));
          

          輸出結(jié)果如下:

          在 Promise 中,catch 是用來(lái)處理錯(cuò)誤的。除了 catch 還有 finally,類似于 try/catch 中的finally。不管 Promise 結(jié)果如何,finally 都會(huì)執(zhí)行:

          toUppercase(99)
            .then(result => result)
            .catch(error => console.error(error.message))
            .finally(() => console.log("Finally"));
          

          輸出結(jié)果如下:

          需要記住,任何傳遞給 then/catch/finally 的回調(diào)都是由微任務(wù)隊(duì)列異步處理的。 它們是微任務(wù),優(yōu)先于事件和計(jì)時(shí)器等宏任務(wù)。

          (5)Promise, error, throw

          作為拒絕 Promise 時(shí)的最佳實(shí)踐,可以傳入 error 對(duì)象:

          Promise.reject(TypeError("Expected string"));
          

          這樣,在整個(gè)代碼庫(kù)中保持錯(cuò)誤處理的一致性。 其他團(tuán)隊(duì)成員總是可以訪問(wèn) error.message,更重要的是可以檢查堆棧跟蹤。

          除了 Promise.reject 之外,還可以通過(guò)拋出異常來(lái)退出 Promise 執(zhí)行鏈。來(lái)看下面的例子:

          Promise.resolve("A string").then(value => {
            if (typeof value === "string") {
              throw TypeError("Expected number!");
            }
          });
          

          這里使用 字符串來(lái) resolve 一個(gè) Promise,然后執(zhí)行鏈立即使用 throw 斷開(kāi)。為了停止異常的傳播,可以使用 catch 來(lái)捕獲錯(cuò)誤:

          Promise.resolve("A string")
            .then(value => {
              if (typeof value === "string") {
                throw TypeError("Expected number!");
              }
            })
            .catch(reason => console.log(reason.message));
          

          這種模式在 fetch 中很常見(jiàn),可以通過(guò)檢查 response 對(duì)象來(lái)查找錯(cuò)誤:

          fetch("https://example-dev/api/")
            .then(response => {
              if (!response.ok) {
                throw Error(response.statusText);
              }
          
              return response.json();
            })
            .then(json => console.log(json));
          

          這里的異常可以使用 catch 來(lái)攔截。 如果失敗了,并且沒(méi)有攔截它,異常就會(huì)在堆棧中向上冒泡。這本身并沒(méi)有什么問(wèn)題,但不同的環(huán)境對(duì)未捕獲的拒絕有不同的反應(yīng)。

          例如,Node.js 會(huì)讓任何未處理 Promise 拒絕的程序崩潰:

          DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
          

          所以,最好去捕獲錯(cuò)誤。

          (6)使用 Promise 處理定時(shí)器錯(cuò)誤

          對(duì)于計(jì)時(shí)器或事件,不能捕獲回調(diào)拋出的異常。上面有一個(gè)例子:

          function failAfterOneSecond() {
            setTimeout(() => {
              throw Error("Error");
            }, 1000);
          }
          
          // 不生效
          try {
            failAfterOneSecond();
          } catch (error) {
            console.error(error.message);
          }
          

          我們可以使用 Promise 來(lái)包裝計(jì)時(shí)器:

          function failAfterOneSecond() {
            return new Promise((_, reject) => {
              setTimeout(() => {
                reject(Error("Error"));
              }, 1000);
            });
          }
          

          這里通過(guò) reject 捕獲了一個(gè) Promise 拒絕,它帶有一個(gè) error 對(duì)象。此時(shí)就可以用 catch 來(lái)處理異常了:

          failAfterOneSecond().catch(reason => console.error(reason.message));
          

          這里使用 value 作為 Promise 的返回值,使用 reason 作為拒絕的返回對(duì)象。

          (7)Promise.all 的錯(cuò)誤處理

          Promise.all 方法接受一個(gè) Promise 數(shù)組,并返回所有解析 Promise 的結(jié)果數(shù)組:

          const promise1 = Promise.resolve("one");
          const promise2 = Promise.resolve("two");
          
          Promise.all([promise1, promise2]).then((results) => console.log(results));
          
          // 結(jié)果: ['one', 'two']
          

          如果這些 Promise 中的任何一個(gè)被拒絕,Promise.all 將拒絕并返回第一個(gè)被拒絕的 Promise 的錯(cuò)誤。

          為了在 Promise.all 中處理這些情況,可以使用 catch:

          const promise1 = Promise.resolve("good");
          const promise2 = Promise.reject(Error("Bad"));
          const promise3 = Promise.reject(Error("Bad+"));
          
          Promise.all([promise1, promise2, promise3])
            .then(results => console.log(results))
            .catch(error => console.error(error.message));
          

          如果想要運(yùn)行一個(gè)函數(shù)而不考慮 Promise.all 的結(jié)果,可以使用 finally:

          Promise.all([promise1, promise2, promise3])
            .then(results => console.log(results))
            .catch(error => console.error(error.message))
            .finally(() => console.log("Finally"));
          

          (8)Promise.any 的錯(cuò)誤處理

          Promise.any 和 Promise.all 恰恰相反。Promise.all 如果某一個(gè)失敗,就會(huì)拋出第一個(gè)失敗的錯(cuò)誤。而 Promise.any 總是返回第一個(gè)成功的 Promise,無(wú)論是否發(fā)生任何拒絕。

          相反,如果傳遞給 Promise.any 的所有 Promise 都被拒絕,那產(chǎn)生的錯(cuò)誤就是 AggregateError。 來(lái)看下面的例子:

          const promise1 = Promise.reject(Error("Error"));
          const promise2 = Promise.reject(Error("Error+"));
          
          Promise.any([promise1, promise2])
            .then(result => console.log(result))
            .catch(error => console.error(error))
            .finally(() => console.log("Finally"));
          

          輸出結(jié)果如下:

          這里用 catch 處理錯(cuò)誤。AggregateError 對(duì)象具有與基本錯(cuò)誤相同的屬性,外加一個(gè) errors 屬性:

          const promise1 = Promise.reject(Error("Error"));
          const promise2 = Promise.reject(Error("Error+"));
          
          Promise.any([promise1, promise2])
            .then(result => console.log(result))
            .catch(error => console.error(error.errors))
            .finally(() => console.log("Finally"));
          

          此屬性是一個(gè)包含所有被拒絕的錯(cuò)誤信息的數(shù)組:

          (9)Promise.race 的錯(cuò)誤處理

          Promise.race 接受一個(gè) Promise 數(shù)組,并返回第一個(gè)成功的 Promise 的結(jié)果:

          const promise1 = Promise.resolve("one");
          const promise2 = Promise.resolve("two");
          
          Promise.race([promise1, promise2]).then(result => 
            console.log(result)
          );
          
          // 結(jié)果:one
          

          那如果有被拒絕的 Promise,但它不是傳入數(shù)組中的第一個(gè)呢:

          const promise1 = Promise.resolve("one");
          const rejection = Promise.reject(Error("Bad"));
          const promise2 = Promise.resolve("two");
          
          Promise.race([promise1, rejection, promise2]).then(result =>
            console.log(result)
          );
          
          // 結(jié)果:one
          

          這樣結(jié)果還是 one,不會(huì)影響正常的執(zhí)行。

          如果被拒絕的 Promise 是數(shù)組的第一個(gè)元素,則 Promise.race 拒絕,就必須要必須捕獲拒絕:

          const promise1 = Promise.resolve("one");
          const rejection = Promise.reject(Error("Bad"));
          const promise2 = Promise.resolve("two");
          
          Promise.race([rejection, promise1, promise2])
            .then(result => console.log(result))
            .catch(error => console.error(error.message));
          
          // Bad
          

          (10)Promise.allSettled 的錯(cuò)誤處理

          Promise.allSettled 是 ECMAScript 2020 新增的 API。它和 Promise.all 類似,不過(guò)不會(huì)被短路,也就是說(shuō)當(dāng)Promise全部處理完成后,可以拿到每個(gè) Promise 的狀態(tài), 而不管其是否處理成功。

          來(lái)看下面的例子:

          const promise1 = Promise.resolve("Good!");
          const promise2 = Promise.reject(Error("Bad!"));
          
          Promise.allSettled([promise1, promise2])
            .then(results => console.log(results))
            .catch(error => console.error(error))
            .finally(() => console.log("Finally"));
          

          這里向 Promise.allSettled 傳遞了一個(gè)包含兩個(gè) Promise 的數(shù)組:一個(gè)已解決,另一個(gè)已拒絕。

          輸出結(jié)果如下:

          (11)async/await 的錯(cuò)誤處理

          JavaScript 中的 async/await 表示異步函數(shù),用同步的方式去編寫(xiě)異步,可讀性更好。

          下面來(lái)改編上面的同步函數(shù) toUppercase,通過(guò)將 async 放在 function 關(guān)鍵字之前將其轉(zhuǎn)換為異步函數(shù):

          async function toUppercase(string) {
            if (typeof string !== "string") {
              throw TypeError("Expected string");
            }
          
            return string.toUpperCase();
          }
          

          只需在 function 前加上 async 前綴,就可以讓函數(shù)返回一個(gè) Promise。這意味著我們可以在函數(shù)調(diào)用之后鏈?zhǔn)秸{(diào)用 then、catch 和 finally:

          toUppercase("hello")
            .then(result => console.log(result))
            .catch(error => console.error(error.message))
            .finally(() => console.log("Always runs!"));
          

          當(dāng)從 async 函數(shù)中拋出異常時(shí),異常會(huì)成為底層 Promise 被拒絕的原因。任何錯(cuò)誤都可以從外部用 catch 攔截。

          除此之外,還可以使用 try/catch/finally 來(lái)處理錯(cuò)誤,就像在同步函數(shù)中一樣。

          例如,從另一個(gè)函數(shù) consumer 中調(diào)用 toUppercase,它方便地用 try/catch/finally 包裝了函數(shù)調(diào)用:

          async function toUppercase(string) {
            if (typeof string !== "string") {
              throw TypeError("Expected string");
            }
          
            return string.toUpperCase();
          }
          
          async function consumer() {
            try {
              await toUppercase(98);
            } catch (error) {
              console.error(error.message);
            } finally {
              console.log("Finally");
            }
          }
          
          consumer();
          

          輸出結(jié)果如下:

          (12)異步生成器的錯(cuò)誤處理

          JavaScript 中的異步生成器是能夠生成 Promise 而不是簡(jiǎn)單值的生成器函數(shù)。它將生成器函數(shù)與異步相結(jié)合,結(jié)果是一個(gè)生成器函數(shù),其迭代器對(duì)象向消費(fèi)者公開(kāi)一個(gè) Promise。

          要?jiǎng)?chuàng)建一個(gè)異步生成器,需要聲明一個(gè)帶有星號(hào) * 的生成器函數(shù),前綴為 async:

          async function* asyncGenerator() {
            yield 33;
            yield 99;
            throw Error("Bad!"); // Promise.reject
          }
          

          因?yàn)楫惒缴善魇腔?Promise,所以同樣適用 Promise 的錯(cuò)誤處理規(guī)則,在異步生成器中,throw 會(huì)導(dǎo)致 Promise 拒絕,可以用 catch 攔截它。

          要想從異步生成器處理 Promise,可以使用 then:

          const go = asyncGenerator();
          
          go.next().then(value => console.log(value));
          go.next().then(value => console.log(value));
          go.next().catch(reason => console.error(reason.message));
          

          輸出結(jié)果如下:

          也使用異步迭代 for await...of。 要使用異步迭代,需要用 async 函數(shù)包裝 consumer:

          async function* asyncGenerator() {
            yield 33;
            yield 99;
            throw Error("Bad"); // Promise.reject
          }
          
          async function consumer() {
            for await (const value of asyncGenerator()) {
              console.log(value);
            }
          }
          
          consumer();
          

          與 async/await 一樣,可以使用 try/catch 來(lái)處理任何異常:

          async function* asyncGenerator() {
            yield 33;
            yield 99;
            throw Error("Bad"); // Promise.reject
          }
          
          async function consumer() {
            try {
              for await (const value of asyncGenerator()) {
                console.log(value);
              }
            } catch (error) {
              console.error(error.message);
            }
          }
          
          consumer();
          

          輸出結(jié)果如下:

          從異步生成器函數(shù)返回的迭代器對(duì)象也有一個(gè) throw() 方法。在這里對(duì)迭代器對(duì)象調(diào)用 throw() 不會(huì)拋出異常,而是 Promise 拒絕:

          async function* asyncGenerator() {
            yield 33;
            yield 99;
            yield 11;
          }
          
          const go = asyncGenerator();
          
          go.next().then(value => console.log(value));
          go.next().then(value => console.log(value));
          
          go.throw(Error("Reject!"));
          
          go.next().then(value => console.log(value)); 
          

          輸出結(jié)果如下:

          可以通過(guò)以下方式來(lái)捕獲錯(cuò)誤:

          go.throw(Error("Let's reject!")).catch(reason =>
            console.error(reason.message)
          );
          

          我們知道,迭代器對(duì)象的 throw() 是在生成器內(nèi)部發(fā)送異常的。所以還可以使用以下方式來(lái)處理錯(cuò)誤:

          async function* asyncGenerator() {
            try {
              yield 33;
              yield 99;
              yield 11;
            } catch (error) {
              console.error(error.message);
            }
          }
          
          const go = asyncGenerator();
          
          go.next().then(value => console.log(value));
          go.next().then(value => console.log(value));
          
          go.throw(Error("Reject!"));
          
          go.next().then(value => console.log(value));
          

          5. Node.js 錯(cuò)誤處理

          (1)同步錯(cuò)誤處理

          Node.js 中的同步錯(cuò)誤處理與 JavaScript 是一樣的,可以使用 try/catch/finally。

          (2)異步錯(cuò)誤處理:回調(diào)模式

          對(duì)于異步代碼,Node.js 強(qiáng)烈依賴兩個(gè)術(shù)語(yǔ):

          • 事件發(fā)射器
          • 回調(diào)模式

          在回調(diào)模式中,異步 Node.js API 接受一個(gè)函數(shù),該函數(shù)通過(guò)事件循環(huán)處理并在調(diào)用堆棧為空時(shí)立即執(zhí)行。

          來(lái)看下面的例子:

          const { readFile } = require("fs");
          
          function readDataset(path) {
            readFile(path, { encoding: "utf8" }, function(error, data) {
              if (error) console.error(error);
              // data操作
            });
          }
          

          這里可以看到回調(diào)中錯(cuò)誤處理:

          function(error, data) {
              if (error) console.error(error);
              // data操作
          }
          

          如果使用 fs.readFile 讀取給定路徑時(shí)出現(xiàn)任何錯(cuò)誤,我們都會(huì)得到一個(gè) error 對(duì)象。這時(shí)我們可以:

          • 單地記錄錯(cuò)誤對(duì)象。
          • 拋出異常。
          • 將錯(cuò)誤傳遞給另一個(gè)回調(diào)。

          要想拋出異常,可以這樣做:

          const { readFile } = require("fs");
          
          function readDataset(path) {
            readFile(path, { encoding: "utf8" }, function(error, data) {
              if (error) throw Error(error.message);
              // data操作
            });
          }
          

          但是,與 DOM 中的事件和計(jì)時(shí)器一樣,這個(gè)異常會(huì)使程序崩潰。 使用 try/catch 停止它的嘗試將不起作用:

          const { readFile } = require("fs");
          
          function readDataset(path) {
            readFile(path, { encoding: "utf8" }, function(error, data) {
              if (error) throw Error(error.message);
              // data操作
            });
          }
          
          try {
            readDataset("not-here.txt");
          } catch (error) {
            console.error(error.message);
          }
          

          如果不想讓程序崩潰,可以將錯(cuò)誤傳遞給另一個(gè)回調(diào):

          const { readFile } = require("fs");
          
          function readDataset(path) {
            readFile(path, { encoding: "utf8" }, function(error, data) {
              if (error) return errorHandler(error);
              // data操作
            });
          }
          

          這里的 errorHandler 是一個(gè)簡(jiǎn)單的錯(cuò)誤處理函數(shù):

          function errorHandler(error) {
            console.error(error.message);
            // 處理錯(cuò)誤:寫(xiě)入日志、發(fā)送到外部logger
          }
          

          (3)異步錯(cuò)誤處理:事件發(fā)射器

          Node.js 中的大部分工作都是基于事件的。大多數(shù)時(shí)候,我們會(huì)與發(fā)射器對(duì)象和一些偵聽(tīng)消息的觀察者進(jìn)行交互。

          Node.js 中的任何事件驅(qū)動(dòng)模塊(例如 net)都擴(kuò)展了一個(gè)名為 EventEmitter 的根類。EventEmitter 有兩個(gè)基本方法:on 和 emit。

          下面來(lái)看一個(gè)簡(jiǎn)單的 HTTP 服務(wù)器:

          const net = require("net");
          
          const server = net.createServer().listen(8081, "127.0.0.1");
          
          server.on("listening", function () {
            console.log("Server listening!");
          });
          
          server.on("connection", function (socket) {
            console.log("Client connected!");
            socket.end("Hello client!");
          });
          

          這里我們監(jiān)聽(tīng)了兩個(gè)事件:listening 和 connection。除了這些事件之外,事件發(fā)射器還公開(kāi)一個(gè)錯(cuò)誤事件,在出現(xiàn)錯(cuò)誤時(shí)觸發(fā)。

          如果這段代碼監(jiān)聽(tīng)的端口是 80,就會(huì)得到一個(gè)異常:

          const net = require("net");
          
          const server = net.createServer().listen(80, "127.0.0.1");
          
          server.on("listening", function () {
            console.log("Server listening!");
          });
          
          server.on("connection", function (socket) {
            console.log("Client connected!");
            socket.end("Hello client!");
          });
          

          輸出結(jié)果如下:

          events.js:291
                throw er;
                ^
          
          Error: listen EACCES: permission denied 127.0.0.1:80
          Emitted 'error' event on Server instance at: ...
          

          為了捕獲它,可以為 error 注冊(cè)一個(gè)事件處理函數(shù):

          server.on("error", function(error) {
            console.error(error.message);
          });
          

          這樣就會(huì)輸出:

          listen EACCES: permission denied 127.0.0.1:80
          

          6. 錯(cuò)誤處理最佳實(shí)踐

          最后,我們來(lái)看看處理 JavaScript 異常的最佳實(shí)踐!

          (1)不要過(guò)度處理錯(cuò)誤

          錯(cuò)處理的第一個(gè)最佳實(shí)踐就是不要過(guò)度使用“錯(cuò)誤處理”。通常,我們會(huì)在外層處理錯(cuò)誤,從內(nèi)層拋出錯(cuò)誤,這樣一旦出現(xiàn)錯(cuò)誤,就可以更好地理解是什么原因?qū)е碌摹?/span>

          然而,開(kāi)發(fā)人員常犯的錯(cuò)誤之一是過(guò)度使用錯(cuò)誤處理。有時(shí)這樣做是為了讓代碼在不同的文件和方法中看起來(lái)保持一致。但是,不幸的是,這些會(huì)對(duì)應(yīng)用程序和錯(cuò)誤檢測(cè)造成不利影響。

          因此,只關(guān)注代碼中可能導(dǎo)致錯(cuò)誤的地方,錯(cuò)誤處理將有助于提高代碼健壯性并增加檢測(cè)到錯(cuò)誤的機(jī)會(huì)。

          (2)避免瀏覽器特定的非標(biāo)準(zhǔn)方法

          盡管許多瀏覽器都遵循一個(gè)通用標(biāo)準(zhǔn),但某些特定于瀏覽器的 JavaScript 實(shí)現(xiàn)在其他瀏覽器上卻失敗了。例如,以下語(yǔ)法僅適用于 Firefox:

          catch(e) { 
            console.error(e.filename + ': ' + e.lineNumber); 
          }
          

          因此,在處理錯(cuò)誤時(shí),盡可能使用跨瀏覽器友好的 JavaScript 代碼。

          (3)遠(yuǎn)程錯(cuò)誤記錄

          當(dāng)發(fā)生錯(cuò)誤時(shí),我們應(yīng)該得到通知以了解出了什么問(wèn)題。這就是錯(cuò)誤日志的用武之地。JavaScript 代碼是在用戶的瀏覽器中執(zhí)行的。因此,需要一種機(jī)制來(lái)跟蹤客戶端瀏覽器中的這些錯(cuò)誤,并將它們發(fā)送到服務(wù)器進(jìn)行分析。

          可以嘗試使用以下工具來(lái)監(jiān)控并上報(bào)錯(cuò)誤:

          • Sentry(https://sentry.io/): 專注于異常(應(yīng)用崩潰)而不是信息錯(cuò)誤。它提供了應(yīng)用中錯(cuò)誤的完整概述,包括受影響的用戶數(shù)量、調(diào)用堆棧、受影響的瀏覽器以及導(dǎo)致錯(cuò)誤的提交等詳細(xì)信息。
          • Rollbar(https://rollbar.com/): 用于前端、后端和移動(dòng)應(yīng)用的無(wú)代理錯(cuò)誤監(jiān)控工具。它提供人工智能輔助的工作流程,使開(kāi)發(fā)人員能夠在錯(cuò)誤影響用戶之前立即采取行動(dòng)。它會(huì)顯示受錯(cuò)誤影響的客戶數(shù)量、受影響的平臺(tái)或?yàn)g覽器的類型以及之前是否發(fā)生過(guò)類似錯(cuò)誤或是否已經(jīng)存在解決方案等數(shù)據(jù)。

          (4)錯(cuò)誤處理中間件(Node.js)

          Node.js 環(huán)境支持使用中間件向服務(wù)端應(yīng)用中添加功能。因此可以創(chuàng)建一個(gè)錯(cuò)誤處理中間件。使用中間件的最大好處是所有錯(cuò)誤都在一個(gè)地方集中處理。可以選擇啟用/禁用此設(shè)置以輕松進(jìn)行測(cè)試。

          以下是創(chuàng)建基本中間件的方法:

          const logError = err => {
              console.log("ERROR: " + String(err))
          }
          
          const errorLoggerMiddleware = (err, req, res, next) => {
              logError(err)
              next(err)
          }
          
          const returnErrorMiddleware = (err, req, res, next) => {
              res.status(err.statusCode || 500)
                 .send(err.message)
          }
          
          module.exports = {
              logError,
              errorLoggerMiddleware,
              returnErrorMiddleware
          }
          

          可以像下面這樣在應(yīng)用中使用此中間件:

          const { errorLoggerMiddleware, returnErrorMiddleware } = require('./errorMiddleware')
          
          app.use(errorLoggerMiddleware)
          
          app.use(returnErrorMiddleware)
          

          現(xiàn)在可以在中間件內(nèi)定義自定義邏輯以適當(dāng)?shù)靥幚礤e(cuò)誤。而無(wú)需再擔(dān)心在整個(gè)代碼庫(kù)中實(shí)現(xiàn)單獨(dú)的錯(cuò)誤處理結(jié)構(gòu)。

          (5)捕獲所有未捕獲的異常(Node.js)

          我們可能永遠(yuǎn)無(wú)法涵蓋應(yīng)用中可能發(fā)生的所有錯(cuò)誤。因此,必須實(shí)施回退策略以捕獲應(yīng)用中所有未捕獲的異常。

          可以這樣做:

          process.on('uncaughtException', error => {
              console.log("ERROR: " + String(error))
              // 其他處理機(jī)制
          })
          

          還可以確定發(fā)生的錯(cuò)誤是標(biāo)準(zhǔn)錯(cuò)誤還是自定義操作錯(cuò)誤。根據(jù)結(jié)果,可以退出進(jìn)程并重新啟動(dòng)它以避免意外行為。

          (6)捕獲所有未處理的 Promise 拒絕(Node.js)

          與異常不同的是,promise 拒絕不會(huì)拋出錯(cuò)誤。因此,一個(gè)被拒絕的 promise 可能只是一個(gè)警告,這讓?xiě)?yīng)用有可能遇到意外行為。因此,實(shí)現(xiàn)處理 promise 拒絕的回退機(jī)制至關(guān)重要。

          可以這樣做:

          const promiseRejectionCallback = error => {
              console.log("PROMISE REJECTED: " + String(error))
          }
          
          process.on('unhandledRejection', callback)
          

          參考文章

          • https://www.valentinog.com/blog/error/
          • https://kinsta.com/blog/errors-in-javascript/
          • https://blog.bitsrc.io/javascript-exception-handling-patterns-best-practices-f7d6fcab735d

          個(gè)漂亮的警告頁(yè)面模板,轉(zhuǎn)載自:折影輕夢(mèng),用來(lái)作為跳轉(zhuǎn)提示或者改一改用作404頁(yè)面什么的都挺好的,試試看吧!

          效果圖

          下面兩張圖是我改了改配色,你們看看效果

          演示地址

          https://www.tiezi.xyz/html/a1/tishi.html

          模板下載

          關(guān)注我的頭條號(hào),然后私信回復(fù) 1270 ,即可獲取下載地址。


          主站蜘蛛池模板: 福利一区二区在线| 亚洲线精品一区二区三区影音先锋| 蜜桃AV抽搐高潮一区二区| 色综合视频一区二区三区44| 国产精品亚洲专区一区| 国产美女一区二区三区| 手机看片福利一区二区三区| 国产无吗一区二区三区在线欢| 亚洲视频一区在线| 无码人妻视频一区二区三区| www一区二区www免费| 无码人妻精品一区二区三区99不卡 | 国产一区二区三区精品视频| 国内精品一区二区三区在线观看 | 精品乱人伦一区二区三区| 国产精品成人一区二区三区| 精品一区二区三区四区在线播放 | 99精品国产一区二区三区2021| 国产日韩一区二区三区在线观看| 国产一区二区三区在线看片| 亚洲色无码专区一区| 亚洲欧美日韩中文字幕在线一区 | 亚洲av无码一区二区三区乱子伦| 国产激情一区二区三区| 美女免费视频一区二区| 日韩国产一区二区| 亚洲国产综合精品一区在线播放| 偷拍精品视频一区二区三区| 国产在线精品观看一区| 一区二区在线视频免费观看| 国产精品 视频一区 二区三区| 亚洲免费一区二区| 精品国产日韩亚洲一区| 在线观看午夜亚洲一区| 久久亚洲一区二区| 日韩免费一区二区三区在线| 国模无码视频一区| 成人区人妻精品一区二区不卡网站 | 亚洲va乱码一区二区三区| 国产经典一区二区三区蜜芽 | 精品人妻少妇一区二区三区在线|