【小貼士】【stringify神BUG】【localstorage失效】【消滅Safari alert框】【是否延遲加載】【頁面10px白屏】


前言

最近碰到幾個惡心問題,也發現一點優化技巧,以及對Hybrid知識的一些整理,這里便一並拿出來做分享了,關於Hybrid的調試,會是我今后一個重點
我的博客首先是學習筆記,方便自己做知識沉淀,以后好查閱,其次才是分享,所以其中有誤請提出,覺得亂是很有可能的~~~~~~
我們在工作中一般會有這么一個流程:發現問題->定位問題->解決問題
其中最難就是定位問題,有時候我們會花上幾天時間定位問題,而解決問題卻只需要幾秒......
所以定位問題的能力非常重要,這也是經驗的體現,所謂高手其實就是坑踩得多而又善於總結罷了
我這里首先分享一個坑爹的問題,然后由此問題展開今天的學習

JSON.stringify出BUG啦!

沒錯,這個我最近碰到最為惡心的一個問題!!!
所有頁面,本來在手機上好好的,就算所有手機、奇葩機都測試通過了,最后Hybrid聯調時總會出兩個莫名其妙的BUG
PS:不知道Hybrid各位聽過么?沒有聽過的前端需要好好補補課了,最近2年這個可能是一大趨勢,在與Hybrid的戰斗中,Hybrid表現出了移動開發萬惡之源的應有素質,配合索尼小米三星組成了一個難以逾越的障礙牆(UC我們就不提了)
問題的現象是,一個服務器下發的數據對象被存到了localstorage中,拿出來后其中的小數變成null了
該問題暫時發現發生於 Hybrid  三星S3 Sony L39H中,應該還有不少其它低端機型有問題。
幾經定位發現現象如下:
var testObject1 = {
  OrderAmount: 0.11
};
JSON.stringify(testObject1) => OrderAmount: null
① 進頁面便觸發這段代碼不會出問題~~
② click事件中執行上面代碼在60%的概率中便中招了!
最初我當然不相信原生的JSON.stringify會出問題,便反復測試,反復定位,最后頁面的代碼刪到只有幾行的時候,我不得不承認是他出了問題~~~~~~Hybrid就是讓你料想不到
一旦定位問題后,這里的解決方案也便出來了:
在Hybrid中判斷useAgent,重寫掉JSON.stringify的邏輯即可,這里貼一段參考代碼:
var json2 = {
  type: function (obj) {
    if (obj == null) return String(obj);
    var h = { '[object Boolean]': 'boolean', '[object Number]': 'number', '[object String]': 'string', '[object Function]': 'function', '[object Array]': 'array', '[object Date]': 'date', '[object RegExp]': 'regexp', '[object Error]': 'error' };
    var t = Object.prototype.toString.call(obj);
    if (t in h) return h[t];
    if (t == '[object Object]') t = obj + '';
    var arr = t.match(/^\[object (HTML\w+)\]$/);
    if (arr) return arr[1];
    return 'object';
  },
  stringifyJSON: function (obj) {
    var str, t = window.JSON;
    var rstringifyJSON = /([\n\r\f\\\/\'\"])/g;
    var arr = [], i = 0, n, p;
    var stringHash = {
      '\n': '\\n',
      '\r': '\\r',
      '\f': '\\f'
    };
    switch (json2.type(obj)) {
      case null:
        str = 'null';
        break;
      case 'undefined':
        str = 'undefined';
        break;
      case 'object':
        for (p in obj) {
          if (obj.hasOwnProperty(p)) {
            arr[i++] = json2.stringifyJSON(p) + ':' + json2.stringifyJSON(obj[p]);
          }
        }
        str = '{' + arr.join(',') + '}';
        break;
      case 'array':
        for (i = 0, n = obj.length; i < n; i++) {
          arr[i] = json2.stringifyJSON(obj[i]);
        }
        str = '[' + arr.join(',') + ']';
        break;
      case 'string':
        str = '\"' + obj.replace(rstringifyJSON, function (a) {
          return stringHash[a] || '\\' + a;
        }) + '\"';
        break;
      case 'date':
        str = 'new Date(' + obj.getTime() + ')';
        break;
      case 'number':
      case 'boolean':
      case 'function':
      case 'regexp':
        str = obj.toString();
        break;
      default:
        str = 'null';
    }
    return str;
  }
};

JSON.stringify = json2.stringifyJSON; 
View Code

當然,我這里其實挖掘的不夠徹底,我只是定位到了JSON.stringify有問題,卻不能再定位里面哪個環節有問題了......

更加優雅的做法:

var stringifyFunc = JSON.stringify
JSON.stringify = function () {
  if (arguments.length == 1) {
    return stringifyFunc.call(this, arguments[0], function (k, v) {
      if (!isNaN(v)) return v + '';
      else return v;
    })
  }
  else {
    stringifyFunc.apply(this, arguments);
  }
}

localstorage讀取失效

上面說到了localstorage,這里正好將它拿出來說下,首先有幾個必須要牢記的規則

① localstorage最大字符為500多萬(5M)
各個手機有所差異,但是不會太大,所以使用localstorage一定要記得清理,不清理可能導致
讀取localstorage效率下降,localstorage滿了會引發業務邏輯錯誤
② localstorage讀取文件的
所以其性能沒有內存讀取快,firefox更是會一次性將數據導入內存,想想就覺得嚇人啊
③ localstorage不被爬蟲識別,所以與SEO相關的關鍵信息需要避免使用localstorage,否則后續會被坑死
上面說了幾個localstorage需要注意的地方,事實上localstorage對性能提升還是有一些作用的
存儲不太重要的數據,比如城市信息;存取1分鍾內有用的數據也是可以減少請求的
但是在android Hybrid中有一個神奇的后退按鈕,此按鈕一旦按下會回到上一個頁面,這個時候里面的localstorage可能會讀取失效!!!一個簡單不靠譜的解決方案是在webapp中加入:
window.onunload = function () { };//不要問我為什么,我也不知道!

最后在開啟隱私模式下時,safari的localstorage讀寫是不可用的,但是qq瀏覽器卻可以,至於原因我就不知道了......

消除鏈接失效時safari alert框

該問題的使用場景首先出現在這里:
導致alert框的出現的原因是我點擊了一個無效鏈接,這個時候Safari便會彈框提示
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title></title>
  <meta name="viewport" content="width=320.1, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no,minimal-ui">
</head>
<body>
<a href="http://www.baidu.com">百度一下</a>
<a href="taobao://wireless">測試無效URL</a>
</body>
</html>

前段時間,小釵的一個同事找到了解決方案,大致做法如下:
 1 <html xmlns="http://www.w3.org/1999/xhtml">
 2 <head>
 3   <title></title>
 4   <meta name="viewport" content="width=320.1, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no,minimal-ui">
 5   <script id="others_zepto_10rc1" type="text/javascript" class="library" src="/js/sandbox/other/zepto.min.js"></script>
 6 </head>
 7 <body>
 8   <a href="http://www.baidu.com">百度一下</a> <a href="taobao://wireless">測試無效URL</a>
 9   <script type="text/javascript">
10     $('a').click(function (e) {
11       var el = $(e.target);
12       var url = el.attr('href');
13       if (url.indexOf('taobao') != -1) {
14         var ifm = document.createElement('iframe');
15         ifm.onload = function () {
16           ifm.contentWindow.document.write('<script>location.href="' + url + '"</' + '' + 'script>');
17         }
18         ifm.src = 'about:blank';
19         document.body.appendChild(ifm);
20       } else {
21         window.location = url;
22       }
23       e.preventDefault();
24     });
25   </script>
26 </body>
27 </html>
View Code

核心代碼在此:

 1     $('a').click(function (e) {
 2       var el = $(e.target);
 3       var url = el.attr('href');
 4       if (url.indexOf('taobao') != -1) {
 5         var ifm = document.createElement('iframe');
 6         ifm.onload = function () {
 7           ifm.contentWindow.document.write('<script>location.href="' + url + '"</' + '' + 'script>');
 8         }
 9         ifm.src = 'about:blank';
10         document.body.appendChild(ifm);
11       } else {
12         window.location = url;
13       }
14       e.preventDefault();

其原理就是iframe中url解析錯誤的話,Safari不太理睬~~~~~~

延遲加載·性能與體驗

以延遲加載來說,最常見的便是圖片延遲加載,但是很多朋友卻不知道為什么要做延遲加載
瀏覽器能同時請求的並發數是有限的,對於手機來說一般是4-6之間,不同型號的手機或者瀏覽器會有所不同,差距不會太大
這個請求數限制存於瀏覽器,所以一處請求卡死,就算新開標簽也會受到影響(手機一般不考慮tab),下面有一個場景:
一個頁面打開,里面有N多圖片,並且有幾個js待加載,這個時候若是圖片先加載的話,圖片會占用js的並發數,從而阻塞頁面的加載~~~~~~
舉個webapp的例子,我們進一個列表頁,加載了15個圖片,用戶點擊列表項booking頁模塊js開始加載(requireJS規則),這個時候業務js需要等待前面圖片加載結束后才能加載,至少需要空閑並發數
所以,圖片是有可能堵塞JS的,這個也是我們做圖片延遲加載的主要原因

首屏載入速度

延遲加載是提升首頁載入速度的一大手段,對於webapp來說,操作會有所不同
webapp中一個個業務view都是一個獨立的js文件,我們能控制第二個view在首頁是否加載
或者說,頁面中用到的組件,我們皆可以按需加載,但這里就有一個情況需要取舍
首屏快,操作慢VS首屏慢操作快
說得多不如親身操作:
  
第一個便是首屏快的代碼,其它組件全部采用按需加載的手段,但是事實上這類做法會導致后續操作十分卡!!因為每一個操作可能引發一次請求!
第二個便是首屏將UI與View業務代碼全部打包一起了,這樣首屏加載會比較慢,他的效果時后續操作的無縫性
當然,是否需要將js全部打包,這會是一場口水戰,直接有一個閥值,有一個區間,只要做到這個區間便好

統計代碼導致10px白屏

很多大型網站都會具有統計代碼,而此類統計代碼一般是以img做請求發出,但是他可以導致10px白屏你知道嗎?

會出現10px左右的白屏區域,這個問題導致的原因是:
獨立的inline元素出現時,會為他創建一個line boxes,這個就是傳說中的文字框
一行文字有一個line boxes,line boxes的高度由line-height控制而不是行內元素的width height控制
所以,img的高度與line boxes沒有關系
下面那一行白屏空間其實就是一個匿名line boxes,這個時候給body設置line-height他便會消失,或者讓img脫離文檔流即可

結語

依舊這句話,問題的定位才是難點,若能定位一個問題,其解決方案往往是分分鍾的事情......
這里記錄這些奇怪的知識點,以便今后查閱,也希望對各位有所幫助!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM