<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                [TOC] # Error > 在開發過程中,經常需要我們自己的錯誤類,用于描述任務中可能發生錯誤的特別內容。如網絡操作錯誤,可能需要`HttpError`,數據庫操作錯誤`DbError`以及搜索操作錯誤`NotFoundError`等等。<br> 我們的錯誤應該支持基本的錯誤屬性,如:`message`,`name`以及更詳細的`stack`,也可能有其他屬性,如`HttpError`對象可能有`statusCode`屬性,如:`404`、`403`、`500`。<br> Javascript使用throw可以帶任何參數,所以技術上自定義錯誤不需要繼承`Error`,但通過繼承,可以使用`obj instanceof Error`去區別錯誤對象,所以最好使用繼承。<br> 當我們搭建應用時,我們的錯誤自然形成層次結構,舉例,`HttpTimeoutError`可能繼承自`HttpError`等。 <br> ## 擴展Error 舉例,我們考慮函數`readUser(json)`可以讀取用戶數據,下面是一個有效的json數據。 ~~~ let json = `{ "name": "John", "age": 30 }`; ~~~ <br> 使用`JSON.parse`,如果接收到畸形的json,則會拋出`SyntaxError`錯誤。 <br> 函數`readUser(json)`應該不僅讀json,也應該檢查數據。如果沒有必須的屬性或格式錯誤,則為錯誤,我們稱為`ValidationError`。 ~~~ class ValidationError extends Error { constructor(message) { super(message); // 調用父類構造函數 this.name = "ValidationError"; // 設置name屬性 } } ~~~ <br> 嘗試在`readUser(json)`中使用。注意使用 `instanceof` 檢查特定的錯誤類型 ~~~ function readUser(json) { let user = JSON.parse(json); if (!user.age) { throw new ValidationError("No field: age"); } if (!user.name) { throw new ValidationError("No field: name"); } return user; } // Working example with try..catch try { let user = readUser('{ "age": 25 }'); } catch (err) { if (err instanceof ValidationError) { alert("Invalid data: " + err.message); // Invalid data: No field: name } else if (err instanceof SyntaxError) { // (*) alert("JSON Syntax Error: " + err.message); } else { throw err; // unknown error, rethrow it (**) } } ~~~ <br> ## 進一步繼承 創建更具體類`PropertyRequiredError`,針對屬性缺失錯誤,包括具體那個屬性缺失的額外信息。 ~~~ class ValidationError extends Error { constructor(message) { super(message) this.name = 'ValidationError' } } class PropertyRequiredError extends ValidationError { constructor (property) { super(`No property ${property}`) this.name = 'PropertyRequiredError' this.property = property } } function readJSON (data) { var user = JSON.parse(data) if (!user.age) { throw new PropertyRequiredError('age') } if (!user.name) { throw new PropertyRequiredError('name') } return user } try { let user = readJSON('{ "age": 25 }') } catch (err) { if (err instanceof ValidationError) { alert(`Invalid data: ${err.message}`) } else if (err instanceof SyntaxError) { alert(`JSON Syntax Error: ${err.message}`) } else { throw err } } ~~~ <br> 請注意在`PropertyRequiredError`構造函數再次手工給`this.name`賦值。這可能有點冗長,創建每個自定義錯誤都需要賦值:`this.name = <class name>`,但有其他方法,我們創建我們自己的基礎錯誤類,通過賦值`this.constructor.name`給`this.name`,然后再從該類繼承會簡化。 ~~~ class MyError extends Error { constructor(message) { super(message); this.name = this.constructor.name; } } class ValidationError extends MyError { constructor(message) { super(message) } } class PropertyRequiredError extends ValidationError { constructor (property) { super(`No property ${property}`) this.property = property } } ~~~ <br> ## 包裝異常 在處理的過程中有可能有其他錯誤發生。現在我們有了`SyntaxError`和`ValidationError`,但未來,`readUser`函數可能會擴展:新代碼可能會生成其他類型的錯誤。 <br> 我們創建一個`ReadError`來表現這些錯誤,如果在`readUser`內部發生錯誤,捕獲并生成`ReadError`錯誤。同時保留原始錯誤的引用至`cause`屬性。那么外部代碼僅需要檢查`ReadError`。 <br> 下面代碼定義`ReadError`并演示在`try...catch`塊中使用`readUser`。 ~~~ class MyError extends Error { constructor(message) { super(message); this.name = this.constructor.name; } } class ReadError extends MyError { constructor(message, cause) { super(message) this.cause = cause } } class ValidationError extends MyError { constructor(message) { super(message) } } class PropertyRequiredError extends ValidationError { constructor(property) { super(`No property ${property}`) this.property = property } } function validateUser(user) { if (!user.age) { throw new PropertyRequiredError('age') } if (!user.name) { throw new PropertyRequiredError('name') } } function readUser(json) { let user try { user = JSON.parse(json) } catch (err) { if (err instanceof SyntaxError) { throw new ReadError('Syntax Error', err) } else { throw err; } } try { validateUser(user); } catch (err) { if (err instanceof ValidationError) { throw new ReadError('Validation Error', err) } else { throw err } } } try { readUser('{bad json}') } catch (e) { if (e instanceof ReadError) { alert(e) alert(`Original error: ${e.cause}`) } else { throw e } } ~~~ 上面代碼中,`readUser`如描述的一樣工作正常——捕獲syntax和validation錯誤,然后拋出ReadError錯誤,代替之前的未知錯誤重新拋出。 <br> 所以外部代碼檢查`instanceof ReadError`,無需列出所有類型的錯誤。 <br> 這種方法稱為“包裝異常”,因為我們獲得“低級別的異常”并包裝至`ReadError`,對調用代碼來說,更抽象更方便。在面向對象編程中廣泛使用。 <br> ## 總結 * 通常可以從`Error`或其他的內置錯誤類中繼承,只需關心name屬性,不要忘記調用super。 * 大多數時,應該使用instanceof檢查特定錯誤,也支持繼承類。但有時有錯誤對象來自第三方庫,不容易獲得其類,那么name屬性可以被使用。 * 包裝異常被普遍使用,當函數處理低級別異常,并使一個更高級別的對象報告錯誤,低級別異常有時編程對象屬性,如上面示例中的`err.cause`,但沒有嚴格規定。 <br> <br> # Throw ~~~ throw?expression; ~~~ **throw**語句用來拋出一個用戶自定義的異常。當前函數的執行將被停止(**throw**之后的語句將不會執行),并且控制將被傳遞到調用堆棧中的第一個**catch**塊。如果調用者函數中沒有**catch**塊,程序將會終止。 ~~~ try { console.log('before throw error'); throw new Error('throw error'); console.log('after throw error'); } catch (err) { console.log(err.message); } // before throw error // throw error ~~~ <br> <br> # try / catch / finally <br> ~~~ try { try_statements } [catch (exception) { catch_statements }] [finally { finally_statements }] ~~~ <br> ## 只能捕捉運行時錯誤 **try/catch**主要用于捕捉異常。**try/catch**語句包含了一個**try**塊, 和至少有一個**catch**塊或者一個**finally**塊,下面是三種形式的**try**聲明: * try...catch * try...finally * try...catch...finally <br> **try**塊中放入可能會產生異常的語句或函數 <br> **catch**塊中包含要執行的語句,當**try**塊中拋出異常時,**catch**塊會捕捉到這個異常信息,并執行**catch**塊中的代碼,如果在**try**塊中沒有異常拋出,這**catch**塊將會跳過。 <br> **finally**塊在**try**塊和**catch**塊之后執行。無論是否有異常拋出或著是否被捕獲它總是執行。當在**finally**塊中拋出異常信息時會覆蓋掉**try**塊中的異常信息。 <br> ## 不能捕獲異步代碼錯誤 要注意的是try catch只能捕獲同步代碼的異常,對回調,setTimeout,promise等無能為力 ~~~ try { setTimeout(() => { throw new Error("some message"); }, 0); } catch (err) { console.log(err); } // Uncaught Error: some message ~~~ <br> ## Try / Catch 性能 有一個大家眾所周知的反優化模式就是使用**try/catch**。 在V8(其他JS引擎也可能出現相同情況)函數中使用了**try/catch**語句不能夠被V8編譯器優化。參考[http://www.html5rocks.com/en/tutorials/speed/v8/](http://www.html5rocks.com/en/tutorials/speed/v8/) <br> <br> # window.onerror error事件的事件處理程序。針對各種目標的不同類型的錯誤觸發了 Error 事件: * 當JavaScript運行時錯誤(包括語法錯誤)發生時,window會觸發一個ErrorEvent接口的error事件,并執行window.onerror()。 * 當一項資源(如`<img>`或`<script>`)加載失敗,加載資源的元素會觸發一個Event接口的error事件,并執行該元素上的`onerror()`處理函數。這些error事件**不會向上冒泡到window**,不過(至少在Firefox中)能被單一的`window.addEventListener`捕獲。 <br> 加載一個全局的`error`事件處理函數可用于自動收集錯誤報告。 <br> ~~~ window.onerror =?function?(message, source, lineno, colno, error)?{ } ~~~ * `message`:異常信息(字符串) * `source`:發生異常的腳本URL(字符串) * `lineno`:發生異常的行號(數字) * `colno`:發生異常的列號(數字) * `error`:Error對象(對象) <br> **若該函數返回`true`,則阻止執行默認事件處理函數。** <br> 注意:Safari 和 IE10 還不支持在**window.onerror**的回調函數中使用第五個參數,也就是一個**Error**對象并帶有一個追溯棧。 <br> ## 捕獲語法錯誤 window.onerror能捕捉到語法錯誤,但是語法出錯的代碼塊不能跟window.onerror在同一個塊。 只要把window.onerror這個代碼塊分離出去,并且比其他腳本先執行即可捕捉到語法錯誤。 錯誤處理代碼 ~~~ window.onerror = (msg, url, line, col, err) => { console.log(msg); console.log(url); console.log(line); console.log(col); console.dir(err); // return true } ~~~ 業務代碼 ~~~ // 語法錯誤 alert(1 // 異步錯誤 setTimeout(() => { throw new Error("some message"); }, 0); // 運行時錯誤 i < 1 ~~~ ## 跨域資源 當加載自不同域的腳本中發生語法錯誤時,語法錯誤的細節將不會報告,而代之簡單的"Script error."。在某些瀏覽器中,通過在`<script>`使用 **`crossorigin`** 屬性并要求服務器發送適當的 **CORS HTTP** 響應頭,該行為可被覆蓋。一個變通方案是單獨處理"Script error.",告知錯誤詳情僅能通過瀏覽器控制臺查看,無法通過JavaScript訪問。 <br> # Promise中的異常 ## Promise中拋出異常 ~~~ new Promise((resolve,reject)=>{ reject(); }) ~~~ ~~~ Promise.resolve().then((resolve,reject)=>{ reject(); }); ~~~ ~~~ Promise.reject(); ~~~ ~~~ throw?expression; ~~~ <br> ## Promise中捕捉異常 ~~~ promiseObj.then(undefined, (err)=>{ catch_statements }); ~~~ ~~~ promiseObj.catch((exception)=>{ catch_statements }) ~~~ <br> # window.onunhandledrejection `window.onunhandledrejection`與`window.onerror`類似,在一個JavaScript Promise 被**reject**但是沒有**catch**來捕捉這個**reject**時觸發。并且同時捕獲到一些關于異常的信息。 <br> ~~~ window.onunhandledrejection = event => { event.preventDefault(); // 阻止觸發錯誤 console.log(event.reason); // 也可以使用 return true 阻止錯誤 } ~~~ <br> `event`事件是**PromiseRejectionEvent**的實例,它有兩個屬性: * `event.promise`:被 rejected 的 JavaScript Promise * `event.reason`:一個值或 Object 表明為什么 promise 被 rejected,是**Promise.reject()**中的內容。 <br> # window.rejectionhandled 因為**Promise**可以延后調用**catch**方法,若在拋出**reject**時未調用**catch**進行捕捉,但稍后再次調用**catch**,此時會觸發**rejectionhandled**事件。 ~~~ window.onrejectionhandled = event => { console.log('rejection handled'); } let p = Promise.reject(new Error('throw error')); setTimeout(()=>{ p.catch(e=>{console.log(e)}); },1000); // Uncaught (in promise) Error: throw error // 1秒后輸出 // Error: throw error // rejection handled ~~~ <br> <br> # 參考資料 [前端代碼異常監控方案window.onerror](https://blog.csdn.net/wangji5850/article/details/51180314) [JavaScript的異常處理](https://segmentfault.com/a/1190000011481099) [Javascript自定義錯誤,繼承Error](https://blog.csdn.net/neweastsun/article/details/76371061)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看