<font id="zqva1"></font>
<rt id="zqva1"></rt>
  • <tt id="zqva1"></tt>
    <cite id="zqva1"></cite>

    <cite id="zqva1"><noscript id="zqva1"></noscript></cite>
      <rp id="zqva1"><meter id="zqva1"></meter></rp>

        <cite id="zqva1"></cite>
          <b id="zqva1"></b>
          <rp id="zqva1"></rp>
          <cite id="zqva1"></cite>

          <rt id="zqva1"></rt>

        1. <rp id="zqva1"></rp>

          JavaScript的異常處理

          時間:?2017-11-27閱讀:?792標簽:?異常處理

          當 JavaScript 引擎執行 JavaScript 代碼時,有可能會發生各種異常,例如是語法異常,語言中缺少的功能,由于來自服務器或用戶的異常輸出而導致的異常。

          而 Javascript 引擎是單線程的,因此一旦遇到異常,Javascript 引擎通常會停止執行,阻塞后續代碼并拋出一個異常信息,因此對于可預見的異常,我們應該捕捉并正確展示給用戶或開發者。


          Error對象

          throw 和 Promise.reject() 可以拋出字符串類型的異常,而且可以拋出一個 Error 對象類型的異常。

          一個 Error 對象類型的異常不僅包含一個異常信息,同時也包含一個追溯棧這樣你就可以很容易通過追溯棧找到代碼出錯的行數了。

          所以推薦拋出 Error 對象類型的異常,而不是字符串類型的異常。

          創建自己的異常構造函數

          function MyError(message) {
              var instance = new Error(message);
              instance.name = 'MyError';
              Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
              return instance;
          }
          
          MyError.prototype = Object.create(Error.prototype, {
              constructor: {
                  value: MyError,
                  enumerable: false,
                  writable: true,
                  configurable: true
              }
          });
          
          if (Object.setPrototypeOf) {
              Object.setPrototypeOf(MyError, Error);
          } else {
              MyError.__proto__ = Error;
          }
          
          export default MyError;

          在代碼中拋出自定義的異常類型并捕捉

          try {
              throw new MyError("some message");
          } catch(e){
              console.log(e.name + ":" + e.message);
          }

          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

          Try / Catch

          try {
             try_statements
          }
          [catch (exception) {
             catch_statements
          }]
          [finally {
             finally_statements
          }]

          try/catch 主要用于捕捉異常。try/catch 語句包含了一個 try 塊, 和至少有一個 catch 塊或者一個 finally 塊,下面是三種形式的 try 聲明:

          • try...catch
          • try...finally
          • try...catch...finally

          try 塊中放入可能會產生異常的語句或函數

          catch 塊中包含要執行的語句,當 try 塊中拋出異常時,catch 塊會捕捉到這個異常信息,并執行 catch 塊中的代碼,如果在 try 塊中沒有異常拋出,這 catch 塊將會跳過。

          finally 塊在 try 塊和 catch 塊之后執行。無論是否有異常拋出或著是否被捕獲它總是執行。當在 finally 塊中拋出異常信息時會覆蓋掉 try 塊中的異常信息。

          try {
              try {
                  throw new Error('can not find it1');
              } finally {
                  throw new Error('can not find it2');
              }
          } catch (err) {
              console.log(err.message);
          }
          
          // can not find it2

          如果從 finally 塊中返回一個值,那么這個值將會成為整個 try-catch-finally 的返回值,無論是否有 return 語句在 try 和 catch 中。這包括在 catch 塊里拋出的異常。

          function test() {
              try {
                  throw new Error('can not find it1');
                  return 1;
              } catch (err) {
                  throw new Error('can not find it2');
                  return 2;
              } finally {
                  return 3;
              }
          }
          
          console.log(test()); // 3

          Try / Catch 性能

          有一個大家眾所周知的反優化模式就是使用 try/catch

          在V8(其他JS引擎也可能出現相同情況)函數中使用了 try/catch 語句不能夠被V8編譯器優化。參考http://www.html5rocks.com/en/tutorials/speed/v8/

          window.onerror

          通過在 window.onerror 上定義一個事件監聽函數,程序中其他代碼產生的未被捕獲的異常往往就會被 window.onerror 上面注冊的監聽函數捕獲到。并且同時捕獲到一些關于異常的信息。

          window.onerror = function (message, source, lineno, colno, error) { }
          • message:異常信息(字符串)
          • source:發生異常的腳本URL(字符串)
          • lineno:發生異常的行號(數字)
          • colno:發生異常的列號(數字)
          • error:Error對象(對象)

          注意:Safari 和 IE10 還不支持在 window.onerror 的回調函數中使用第五個參數,也就是一個 Error 對象并帶有一個追溯棧

          try/catch 不能夠捕獲異步代碼中的異常,但是其將會把異常拋向全局然后 window.onerror 可以將其捕獲。

          try {
              setTimeout(() => {
                  throw new Error("some message");
              }, 0);
          } catch (err) {
              console.log(err);
          }
          // Uncaught Error: some message
          window.onerror = (msg, url, line, col, err) => {
              console.log(err);
          }
          setTimeout(() => {
              throw new Error("some message");
          }, 0);
          // Error: some message

          在Chrome中,window.onerror 能夠檢測到從別的域引用的script文件中的異常,并且將這些異常標記為Script error。如果你不想處理這些從別的域引入的script文件,那么可以在程序中通過Script error標記將其過濾掉。然而,在Firefox、Safari或者IE11中,并不會引入跨域的JS異常,即使在Chrome中,如果使用 try/catch 將這些討厭的代碼包圍,那么Chrome也不會再檢測到這些跨域異常。

          在Chrome中,如果你想通過 window.onerror 來獲取到完整的跨域異常信息,那么這些跨域資源必須提供合適的跨域頭信息。


          Promise中的異常

          Promise中拋出異常

          new Promise((resolve,reject)=>{
              reject();
          })
          Promise.resolve().then((resolve,reject)=>{
              reject();
          });
          Promise.reject();
          throw expression;

          Promise中捕捉異常

          promiseObj.then(undefined, (err)=>{
              catch_statements
          });
          promiseObj.catch((exception)=>{
              catch_statements
          })

          在 JavaScript 函數中,只有 return / yield / throw 會中斷函數的執行,其他的都無法阻止其運行到結束的。

          在 resolve / reject 之前加上 return 能阻止往下繼續運行。

          without return:

          Promise.resolve()
          .then(() => {
              console.log('before excute reject');
              reject(new Error('throw error'));
              console.log('after excute reject');
          })
          .catch((err) => {
              console.log(err.message);
          });
          
          // before excute reject
          // throw error
          // after excute reject

          use return:

          Promise.resolve()
          .then(() => {
              console.log('before excute reject');
              return reject(new Error('throw error'));
              console.log('after excute reject');
          })
          .catch((err) => {
              console.log(err.message);
          });
          
          // before excute reject
          // throw error

          Throw or Reject

          無論是 try/catch 還是 promise 都能捕獲到的是“同步”異常

          reject 是回調,而 throw 只是一個同步的語句,如果在另一個異步的上下文中拋出,在當前上下文中是無法捕獲到的。

          因此在 Promise 中使用 reject 拋出異常。否則 catch 有可能會捕捉不到。

          Promise.resolve()
          .then(() => {
              setTimeout(()=>{
                  throw new Error('throw error');
              },0);
          })
          .catch((err) => {
              console.log(err);
          });
          
          // Uncaught Error: throw error
          Promise.resolve()
          .then(() => {
              return new Promise((resolve, reject) => {
                  setTimeout(() => {
                      reject(new Error('throw error'));
                  }, 0);
              });
          })
          .catch((err) => {
              console.log(err);
          });
          
          // Error: throw error

          window.onunhandledrejection

          window.onunhandledrejection 與 window.onerror 類似,在一個JavaScript Promise 被 reject 但是沒有 catch 來捕捉這個 reject時觸發。并且同時捕獲到一些關于異常的信息。

          window.onunhandledrejection = event => { 
              console.log(event.reason);
          }

          event事件是 PromiseRejectionEvent 的實例,它有兩個屬性:

          • event.promise:被 rejected 的 JavaScript Promise
          • event.reason:一個值或 Object 表明為什么 promise 被 rejected,是 Promise.reject() 中的內容。

          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


          統一異常處理

          代碼中拋出的異常,一種是要展示給用戶,一種是展示給開發者。

          對于展示給用戶的異常,一般使用 alert 或 toast 展示;對于展示給開發者的異常,一般輸出到控制臺。

          在一個函數或一個代碼塊中可以把拋出的異常統一捕捉起來,按照不同的異常類型以不同的方式展示,對于。

          需要點擊確認的異常類型:
          ensureError.js

          function EnsureError(message = 'Default Message') {
              this.name = 'EnsureError';
              this.message = message;
              this.stack = (new Error()).stack;
          }
          EnsureError.prototype = Object.create(Error.prototype);
          EnsureError.prototype.constructor = EnsureError;
          
          export default EnsureError;

          彈窗提示的異常類型:
          toastError.js

          function ToastError(message = 'Default Message') {
              this.name = 'ToastError';
              this.message = message;
              this.stack = (new Error()).stack;
          }
          ToastError.prototype = Object.create(Error.prototype);
          ToastError.prototype.constructor = ToastError;
          
          export default ToastError;

          提示開發者的異常類型:
          devError.js

          function DevError(message = 'Default Message') {
              this.name = 'ToastError';
              this.message = message;
              this.stack = (new Error()).stack;
          }
          DevError.prototype = Object.create(Error.prototype);
          DevError.prototype.constructor = DevError;
          
          export default DevError;

          異常處理器:
          拋出普通異常時,可以帶上 stackoverflow 上問題的列表,方便開發者查找原因。
          errorHandler.js

          import EnsureError from './ensureError.js';
          import ToastError from './toastError.js';
          import DevError from './devError.js';
          import EnsurePopup from './ensurePopup.js';
          import ToastPopup from './toastPopup.js';
          
          function errorHandler(err) {
              if (err instanceof EnsureError) {
                  EnsurePopup(err.message);
              } else if (err instanceof ToastError) {
                  ToastPopup(err.message);
              }else if( err instanceof DevError){
                  DevError(err.message);
              }else{
                  error.message += ` https://stackoverflow.com/questions?q=${encodeURI(error.message)}`
                  console.error(err.message);    
              }
          }
          
          window.onerror = (msg, url, line, col, err) => {
              errorHandler(err);
          }
          
          window.onunhandledrejection = event =>{
              errorHandler(event.reason);
          };
          
          export default errorHandler;

          歡迎關注:Leechikit
          原文鏈接:segmentfault.com

          站長推薦

          1.阿里云: 本站目前使用的是阿里云主機,安全/可靠/穩定。點擊領取2000元代金券、了解最新阿里云產品的各種優惠活動點擊進入

          2.騰訊云: 提供云服務器、云數據庫、云存儲、視頻與CDN、域名等服務。騰訊云各類產品的最新活動,優惠券領取點擊進入

          3.廣告聯盟: 整理了目前主流的廣告聯盟平臺,如果你有流量,可以作為參考選擇適合你的平臺點擊進入

          鏈接: http://www.modern-decoration.com.cn/article/detial/178

          內容以共享、參考、研究為目的,不存在任何商業目的。其版權屬原作者所有,如有侵權或違規,請與小編聯系!情況屬實本人將予以刪除!

          文章投稿關于web前端網站點搜索站長推薦網站地圖站長QQ:522607023

          小程序專欄: 土味情話心理測試腦筋急轉彎幽默笑話段子句子語錄成語大全運營推廣

          国产精品高清视频免费 - 视频 - 在线观看 - 影视资讯 - 唯爱网