js異常處理

為何要處理異常?

提升用戶體驗舀射,及早發(fā)現(xiàn)/定位問題(比如機型怀伦,系統(tǒng)房待,移動端某些無法復(fù)現(xiàn)的問題)

常見異常種類

  1. js 語法錯誤
  2. ajax 請求報錯
  3. 靜態(tài)資源加載異常
  4. promise 異常
  5. iframe 異常
  6. 跨域 Script Error
  7. 崩潰/卡頓

異常處理

  1. try...catch:
  • 只能捕捉到同步的運行時錯誤
// 同步錯誤 ok
try {
  let name = 'name';
  console.log(nam);
} catch (err) {
  console.log(err);
}
  • 不能捕捉到語法錯誤,不能捕捉到異步錯誤
try {
    // 語法錯誤 not ok
  let name = 'jartto;
  console.log(nam);

// 異步錯誤 not ok
//    setTimeout(() => {
//     undefined.map(v => v);
//   }, 1000)
} catch(e) {

  console.log('捕獲到異常:',e);
}
  1. window.onerror:當(dāng) JS 運行時錯誤發(fā)生時拜鹤,window 會觸發(fā)一個 ErrorEvent 接口的 error 事件署惯,并執(zhí)行 window.onerror()镣隶。
    • 可捕捉:同步錯誤,異步錯誤
    • 不可捕捉:語法錯誤轻猖,靜態(tài)資源錯誤域那,接口異常
      注意:
      1. window.onerror 函數(shù)只有在返回 true 的時候,異常才不會向上拋出败许,否則即使是知道異常的發(fā)生控制臺還是會顯示 Uncaught Error: xxxxx
      2. 必須放在所有腳本前面才能捕獲錯誤
// @param {String} message 錯誤信息
// @param {String} source 出錯文件
// @param {Number} lineno 行號
// @param {Number} colno 列號
// @param {Object} error Error 對象(對象)
window.onerror = function (message, source, lineno, colno, error) {
  console.log('捕獲到異常:', { message, source, lineno, colno, error });

  return true;
};
// 同步 ok
throw new Error('error');

// 異步 ok
setTimeout(() => {
  throw new Error('error');
});

// 語法錯誤 not ok
let name = 'name

// 網(wǎng)絡(luò)異常 not ok
let img = new Image()
img.src = './img.png'
  1. window.addEventListener
    當(dāng)一項資源(如圖片或腳本)加載失敗市殷,加載資源的元素會觸發(fā)一個 Event 接口的 error 事件刹衫,并執(zhí)行該元素上的 onerror() 處理函數(shù)。這些 error 事件不會向上冒泡到 window 音羞,不過(至少在 Firefox 中)能被單一的 window.addEventListener 捕獲仓犬。
    注意:

    1. 網(wǎng)絡(luò)請求不會冒泡搀继,所以需要在捕獲階段捕捉到,但是無法判斷 HTTP 狀態(tài)碼民镜,需要配合服務(wù)器日志排查
    2. 避免重復(fù)監(jiān)聽/注意不同瀏覽器的兼容處理
    window.addEventListener(
      'error',
      error => {
        console.log('捕獲到異常:', error);
      },
      true,
    );
    let img = new Image();
    img.src = './img.png';
    img.onload = function (e) {
      console.log(e);
    };
    img.onerror = function (e) {
      console.log(e);
    };
    document.body.appendChild(img);
    
  2. Promise Catch
    在 promise 中可以用 catch 捕捉錯誤险毁,沒有被 catch 的錯誤也無法被 onerror 或 try-catch 捕獲到畔况,為了防止部分 promise 錯誤被漏掉,在全局增加一個 unhandledrejecttion 處理

    window.addEventListener('unhandledrejection', function (e) {
      e.preventDefault(); // 去掉控制臺錯誤顯示
      console.log('捕獲到異常:', e);
      return true;
    });
    Promise.reject('promise error');
    
  3. Vue errorHandler
    捕捉計算屬性/方法運行時錯誤

Vue.config.errorHandler = (err, vm, info) => {
  console.error('通過vue errorHandler捕獲的錯誤');
  console.error(err);
  console.error(vm);
  console.error(info);
};
  1. React componentDidCatch
componentDidCatch(error, info) {
    console.log(error, info);
}
  1. iframe 異常 借助 window.onerror
<iframe src="./iframe.html" frameborder="0"></iframe>
<script>
  window.frames[0].onerror = function (message, source, lineno, colno, error) {
    console.log('捕獲到 iframe 異常:',{message, source, lineno, colno, error});
    return true;
  };
</script>
  1. script error
//  跨源資源共享機制( CORS ):我們?yōu)?script 標(biāo)簽添加 crossOrigin 屬性馋嗜。
<script src='http://jartto.wang/main.js' crossorigin></script>;

// 動態(tài)添加腳本
const script = document.createElement('script');
script.crossOrigin = 'anonymous';
script.src = url;
document.body.appendChild(script);
(() => {
   const originAddEventListener = EventTarget.prototype.addEventListener;
   EventTarget.prototype.addEventListener = function (type, listener, options) {
    // 捕獲添加事件時的堆棧
     const addStack = newError(`Event (${type})`).stack;
      const wrappedListener = function (...args) {
       try {
         return listener.apply(this, args);
       }
       catch (err) {
        // 異常發(fā)生時葛菇,擴展堆棧
         err.stack += '\n' + addStack;
         throw err;
       }
     }
     return originAddEventListener.call(this, type, wrappedListener, options);
   }
 })();
  1. 崩潰和卡頓: window 的 load 和 beforeunload 或者 service worker
    1. 在網(wǎng)頁加載后,不斷更新 session 中的時間济舆,在登出后莺债,將登出態(tài)設(shè)置為正常登出
    2. 判斷上次是否是正常登出齐邦,獲取最后一次時間
// 使用定時器
window.addEventListener('load', function () {
  sessionStorage.setItem('good_exit', 'pending');
  setInterval(function () {
    sessionStorage.setItem('time_before_crash', newDate().toString());
  }, 1000);
});

window.addEventListener('beforeunload', function () {
  sessionStorage.setItem('good_exit', 'true');
});

if (sessionStorage.getItem('good_exit') && sessionStorage.getItem('good_exit') !== 'true') {
  /*
        insert crash logging code here
    */
  alert('Hey, welcome back from your crash, looks like you crashed on: ' + sessionStorage.getItem('time_before_crash'));
}
  1. 錯誤上報
    1. ajax 發(fā)送數(shù)據(jù),但是 ajax 也可能發(fā)生異常
    2. 動態(tài)創(chuàng)建 img
function report(error) {
  let reportUrl = 'http://jartto.wang/report';
  new Image().src = `${reportUrl}?logs=${error}`;
}
3. 優(yōu)化: 過多的錯誤可能導(dǎo)致崩潰我纪, 采集率
Reporter.send = function (data) {
  // 只采集 30%
  if (Math.random() < 0.3) {
    send(data); // 上報錯誤信息
  }
};

總結(jié)

異常處理

  1. try...catch: 可疑區(qū)域監(jiān)控(同步錯誤)
  2. window.onerror : 全局 js 監(jiān)控異常(同步/異步錯誤)
  3. window.addEventListener: 全局監(jiān)控靜態(tài)資源異常(網(wǎng)絡(luò)請求/同步/異步錯誤)
  4. unhandledrejection: 捕獲未 catch 的異常
  5. VUE errorHandler 和 React componentDidCatch
  6. window.load 和 window.beforeunload :監(jiān)控網(wǎng)頁崩潰
  7. 跨域:crossOrigin

參考:https://mp.weixin.qq.com/s/prf-mXexBh1Ie-ctq9FnzA
參考:http://jartto.wang/2018/11/20/js-exception-handling/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末宣羊,一起剝皮案震驚了整個濱河市仇冯,隨后出現(xiàn)的幾起案子族操,更是在濱河造成了極大的恐慌,老刑警劉巖泼舱,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件枷莉,死亡現(xiàn)場離奇詭異笤妙,居然都是意外死亡,警方通過查閱死者的電腦和手機蹲盘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門召衔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人趣席,你說我怎么就攤上這事《疽蹋” “怎么了钉寝?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵嵌纲,是天一觀的道長腥沽。 經(jīng)常有香客問我,道長师溅,這世上最難降的妖魔是什么盾舌? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任妖谴,我火速辦了婚禮,結(jié)果婚禮上嗡载,老公的妹妹穿的比我還像新娘仍稀。我一直安慰自己,他們只是感情好遥巴,可當(dāng)我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布挪哄。 她就那樣靜靜地躺著琉闪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上砂碉,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天增蹭,我揣著相機與錄音磅摹,去河邊找鬼。 笑死饼灿,一個胖子當(dāng)著我的面吹牛帝美,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播庇忌,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼皆疹,長吁一口氣:“原來是場噩夢啊……” “哼抵知!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起残制,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤掖疮,失蹤者是張志新(化名)和其女友劉穎浊闪,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體折汞,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡盖腿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了膏燃。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片何什。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡处渣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出罐栈,到底是詐尸還是另有隱情悠瞬,我是刑警寧澤涯捻,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布障癌,位于F島的核電站,受9級特大地震影響涛浙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜疮薇,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一我注、第九天 我趴在偏房一處隱蔽的房頂上張望但骨。 院中可真熱鬧,春花似錦奔缠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谚攒。三九已至氛堕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間括儒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工锐想, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留帮寻,地道東北人。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓赠摇,卻偏偏與公主長得像固逗,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子藕帜,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容