<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>

          聊一聊 JavaScript 中的錯(cuò)誤隔離

          共 2483字,需瀏覽 5分鐘

           ·

          2021-02-24 18:58


          接口請(qǐng)求失敗、接口中部分?jǐn)?shù)據(jù)缺失、運(yùn)營數(shù)據(jù)不符合預(yù)期… 當(dāng)我們的應(yīng)用發(fā)布上線后,就開始面臨這些風(fēng)險(xiǎn)。

          而一旦這些問題導(dǎo)致了 JavaScript 報(bào)錯(cuò)(如空指針異常),并且沒有被有效地隔離,就有可能引發(fā)頁面的白屏、無法交互等線上問題。

          在雙 11 準(zhǔn)備期間,我們收集了過往一年前端相關(guān)的線上問題,在收集的 21 個(gè)案例中,竟有一半的問題都與「數(shù)據(jù)異常觸發(fā)頁面顯示異?!惯@個(gè)原因有些相關(guān)。

          如何將錯(cuò)誤的影響隔離在一定范圍內(nèi),顯得尤為重要。

          這篇文章就和大家一起來聊一聊我們嘗試過的一些方案,及遇到的問題。

          從空指針異常說起

          數(shù)據(jù)引發(fā)的最常見的問題就是空指針異常。

          var result = a.b.c.d;

          這樣的代碼如同地雷,一旦 a 是一個(gè)動(dòng)態(tài)數(shù)據(jù),那么問題一觸即發(fā)。

          封裝一個(gè) get 的方法來取值,當(dāng)數(shù)據(jù)不存在時(shí),返回 undefined,可以快速避免此類問題。

          var result = get(a, 'b.c.d');

          但如同我們期望大家在取值前,都先做判斷一樣,并不能保證所有人都這么用了,用不用全靠自覺。

          if (a && a.b && a.b.c) {
          ? ?var result = a.b.c.d;
          }

          所以,有了以下的一些方案:

          異步數(shù)據(jù)校驗(yàn)

          對(duì)異步數(shù)據(jù)校驗(yàn)的想法是,在數(shù)據(jù)獲取后、使用前,先做一遍schema校驗(yàn),檢測(cè)重要數(shù)據(jù)缺失、類型不對(duì)等異常情況。

          與此方案對(duì)應(yīng)的,我們?cè)?fetch 的基礎(chǔ)上封裝了 fetch-checker注1 組件。

          fetch-checker 強(qiáng)制要求用戶在請(qǐng)求數(shù)據(jù)的同時(shí),提供數(shù)據(jù)對(duì)應(yīng)的 schema:

          let schema = {
          ? ?"rule": {
          ? ? ?"type": "string",
          ? ?},
          ? ?"banner": {
          ? ? ?"type": "object",
          ? ? ?"required": true,
          ? ? ?"default": {
          ? ? ? ?"url": "https://item.taobao.com/item.htm?id=527331762117"
          ? ? ?}
          ? ?}
          };

          這份 schema 需要描述:

          • 每個(gè)字段的類型

          • 字段是否 required

          • 當(dāng) required 的字段缺失時(shí),是否需要打底數(shù)據(jù)

          fetch-checker 在拿到數(shù)據(jù)后,先做一層校驗(yàn),如有需要的話,補(bǔ)上缺失的數(shù)據(jù),然后再返回給調(diào)用者。這樣,使用者拿到的數(shù)據(jù)就一定是符合預(yù)期的。

          然而,這個(gè)方案面臨的挑戰(zhàn)是:

          1. 如何確保調(diào)用者提供了完整的 schema 描述。

            不想寫 schema,完全可以提供一個(gè)粗略的 schema 描述,來通過校驗(yàn)。

          2. schema 如何精簡(jiǎn)。

            即不會(huì)對(duì) bundle 大小造成太大影響,又能滿足校驗(yàn)的功能。

          代碼編譯

          受 babel 的啟發(fā),這個(gè)方案是對(duì)存在 NPE 隱患的代碼,在編譯階段,將其轉(zhuǎn)換成等價(jià)的安全代碼。如下所示:

          var a = {};

          // input
          var result = a.b.c;

          // output
          var result = (_object2 = (_object3 = a) == null ? null : _object3.b) == null ? null : _object2.c;

          當(dāng) a 為空對(duì)象時(shí),執(zhí)行編譯后的代碼會(huì)返回 null,從而避免因?yàn)榇a拋錯(cuò),阻斷后續(xù)進(jìn)程。

          babel-plugin-safe-member-expression注2 這個(gè) Babel 插件中,我們做了上述的嘗試。目前,cake項(xiàng)目中,已經(jīng)可以通過 enableSafeMemberExpression 這個(gè)配置,選擇性的啟用該功能。

          這個(gè)方案相比來說接入成本較低,開發(fā)者無需對(duì)現(xiàn)有的代碼做出調(diào)整,但同樣存在挑戰(zhàn):

          • 開發(fā)階段問題不易暴露,明明應(yīng)該報(bào)錯(cuò)的場(chǎng)景,卻沒有任何反饋。

            理想的狀態(tài)是:

            開發(fā)調(diào)試階段盡可能多的暴露問題,線上則盡可能的減少報(bào)錯(cuò)。

          • 隱患的代碼如何界定。

            目前所有的 a.b 的調(diào)用方式都會(huì)按上述方案進(jìn)行編譯,雖然測(cè)試過程中還沒有發(fā)現(xiàn)問題,但只處理有隱患的代碼才更安全。

          靜態(tài)校驗(yàn)

          以 flow 為代表的靜態(tài)校驗(yàn)工具,可以在一定程度上檢測(cè)出 NPE 隱患。

          type res = {
          ? ?data ?: Object
          }

          let name = res.data.name;
          // property `name`. Propery cannot be accessed on possibly undefined value

          如上面的代碼所描述的,使用者需要首先理清自己的數(shù)據(jù)是否允許為空值,當(dāng) data 被允許為空值時(shí),通過 flow 檢測(cè),data.name 類似這樣調(diào)用便會(huì)被檢測(cè)出錯(cuò)誤。

          然而,如何來推進(jìn)所有的業(yè)務(wù)都接入靜態(tài)校驗(yàn),接入后,又如何保證開發(fā)者描述了所有的類型,卻同樣是個(gè)難點(diǎn)。

          小結(jié)

          總結(jié)以上幾種方案,各有優(yōu)缺點(diǎn),都還不能算做最理想的解決方案。

          方案名稱優(yōu)勢(shì)缺點(diǎn)
          提前判斷實(shí)行簡(jiǎn)單全靠自覺
          異步數(shù)據(jù)校驗(yàn)可確保所使用的數(shù)據(jù)是滿足預(yù)期的schema 描述成本高
          代碼編譯接入成本低,易執(zhí)行開發(fā)階段不易暴露問題
          靜態(tài)校驗(yàn)對(duì)現(xiàn)有代碼邏輯侵入少落地成本高

          對(duì)于業(yè)務(wù)來說,最愿意使用和有效的方案一定是:

          • 能將線上問題隔離在一個(gè)小范圍內(nèi),同時(shí)不影響開發(fā)調(diào)試階段的問題暴露

          • 能提前暴露出隱患

          • 接入成本低,不需要大量修改現(xiàn)有業(yè)務(wù)代碼

          關(guān)于空指針異常和錯(cuò)誤隔離,機(jī)智的你又有哪些方案,一起來討論吧。

          編者注: 本文提到的所有工具如未提供鏈接,可能是內(nèi)部代碼,暫未對(duì)外公布。

          如果你喜歡探討技術(shù),或者對(duì)本文有任何的意見或建議,非常歡迎加魚頭微信好友一起探討,當(dāng)然,魚頭也非常希望能跟你一起聊生活,聊愛好,談天說地。魚頭的微信號(hào)是:krisChans95 也可以掃碼關(guān)注公眾號(hào),訂閱更多精彩內(nèi)容。
          瀏覽 52
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  一本大道久久久综合精品 | 青娱乐亚洲第一在线 | 精品国产一级A片黄毛网站 | 青娱乐最新偷拍视频 | 免费观看国产一卡二卡电影 |