<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          我發(fā)現(xiàn)了Chrome的一個bug

          共 4517字,需瀏覽 10分鐘

           ·

          2021-07-16 02:01

          故事的開始

          最近在項目中遇到一個問題,業(yè)務邏輯就不在這里介紹了,在排查過程中發(fā)現(xiàn)項目里有類似這樣一段代碼:

          fetch(url)
            .then((res) => res.text())
            .then((text) => {
              const data = JSON.parse(text)
            })

          上面沒有對最后一個then進行catch操作,我們懷疑這里出了問題,因為text可能無法解析為合法的JSON,然而事實上我們的項目里是有全局的錯誤捕獲的:

          window.addEventListener('unhandledrejection', (e) => {
            sendLog(e)
          })

          這就奇怪了,華容逢關(guān)羽嗎?,難道unhandledrejection事件不僅沒有捕獲到JSON.parse的報錯還讓它走脫了嗎?然后我們做了下面這樣代碼的嘗試:

          window.addEventListener('unhandledrejection', event => {
            console.log('unhandledrejection:', event);
          })

          Promise.resolve("{")
            .then((data) => {
              JSON.parse(data)
            })

          在控制臺中出現(xiàn)下下面的報錯信息:

          Uncaught (in promise) SyntaxError: Unexpected end of JSON input
            at JSON.parse (<anonymous>)
            ...

          可以看到這個語法錯誤是因為JSON.parse無法成功解析的緣故,確實是沒有被unhandledrejection捕獲,難道是這個事件出了問題嗎?索性我們直接拋出錯誤,看這個事件能不能正常工作:

          Promise.resolve()
            .then(() => {
              throw 123
            })

          控制臺出現(xiàn)了下面的信息:

          unhandledrejection: 123

          說明unhandledrejection事件是沒問題的,那為什么JSON.parse的錯誤不能捕獲呢?難道是無法捕獲語法錯誤嗎?那我們換一種eval的方式解析JSON,如果無法捕獲語法錯誤,那么eval報的語法錯誤肯定也無法捕獲:

          Promise.resolve("{")
            .then((data) => {
              eval(data)
            })

          我們再看控制臺的輸出:

          unhandledrejection: SyntaxError: Unexpected end of input

          蒙圈了吧,這個語法錯誤居然被捕獲到了,我們又想,難道說JSON.parse的報錯很特殊嗎?我們又做了下面的嘗試:

          Promise.resolve("{")
            .then((data) => {
              try {
                JSON.parse(data)
              } catch (e) {
                throw e
              }
            })

          上面嘗試將報錯通過try...catch...捕獲到,然后再重新拋出,然后控制臺輸出:

          Uncaught (in promise) SyntaxError: Unexpected end of JSON input
            at JSON.parse (<anonymous>)

          上面說明錯誤并沒有被捕獲到,難道是錯誤信息有問題?那我們把錯誤包裝一下呢:

          Promise.resolve("{")
            .then((data) => {
              try {
                JSON.parse(data)
              } catch (e) {
                const wraper = new SyntaxError(e.messgae)
                wraper.stack = e.stack
                throw wraper
              }
            })

          上面創(chuàng)建了一個SyntaxError的實例wraper,然后把try...catch...捕獲到的錯誤信息放到wraper上,拋出wraper,控制臺輸出如下:

          unhandledrejection: SyntaxError: Unexpected end of input

          看起來錯誤被捕獲到了,我們開始懷疑人生,于是在stackoverflow提了這個疑問:stackoverflow問題地址[1],內(nèi)容基本和上文一致,感興趣的同學可以去看看,另外,對于上面問題在FirefoxSafari中并未出現(xiàn)。

          有意思的事

          stackoverflow的評論中,一位叫Kaiido的開發(fā)者說這可能是Chromebug,建議我去chromium bug報告網(wǎng)址[2]報告一下,沒想到我搜索到了類似的報告[3],報告人說他發(fā)現(xiàn)window.onerrorunhandledrejection這兩個事件都無法捕獲到JSON.parse的錯誤:

          window.onerror = async (...args) => {
            console.log("onerror")
          }

          window.addEventListener('unhandledrejection'async function (event{
            console.log("unhandledrejection")
          })

          var elem = document.getElementById('button');
          elem.addEventListener('click', () => { JSON.parse(undefined); })

          上面報告人監(jiān)聽的兩個事件,說最終都沒有被觸發(fā),大家也可以試一下,這個例子由于JSON.parse不在Promise中,所以window.onerror是能夠捕獲的,也就是說報告人的提問不是很恰當,下面維護者的回復就比較搞笑了,這位維護者打開了與報告人相同版本(chrome88)的瀏覽器和黑暗模式,然后打開chrome空白頁,將上面代碼粘貼到控制臺執(zhí)行,然后出現(xiàn)下面報錯:

          Uncaught TypeError: Cannot read property 'addEventListener' of null
            at <anonymous>:11:6

          然后維護者讓報告人指出問題的所在,大家應該都看得出來,這個報錯是因為頁面上沒有button元素導致的,與報告人所說的錯誤沒有任何關(guān)系,所以我懷疑這個維護者是來搞笑的,時隔幾乎一個月,今天上午報告人使用了我在stackoverflow提出的問題作為例子來向維護者說明問題,目前維護者還未回復,大家可以持續(xù)關(guān)注下

          最后

          在上面問題還沒解決的情況下,我們最好還是對現(xiàn)有代碼做一下審查,對于使用Promise的地方在then后面一定要加catch方法,對于直接使用JSON.parse的位置,根據(jù)對參數(shù)的了解情況酌情添加try...catch...

          對于前端錯誤監(jiān)控平臺來說,這也是一個棘手的問題,希望未來能從中看到更好的解決方案。

          封面圖:愚蠢的美人魚 by 鐵柱呆又呆[4]

          參考資料

          [1]

          stackoverflow問題地址: https://stackoverflow.com/questions/68356441/why-unhandledrejection-cant-caught-an-error-from-json-parse

          [2]

          bug報告網(wǎng)址: https://bugs.chromium.org/p/chromium/issues/list

          [3]

          chromium bug報告地址: https://bugs.chromium.org/p/chromium/issues/detail?id=1219363&q=unhandledrejection&can=2

          [4]

          愚蠢的美人魚 by 鐵柱呆又呆: https://www.zcool.com.cn/work/ZNTM0MzQ2NDg=.html


          瀏覽 66
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  99只有精品 | 精品一区二区三区对白 | 99re在线视频免费观看 | 韩国一区二区三区精品 | 伊人久久熟女 |