前言
最近碰到幾個噁心問題,也發現一點優化技巧,以及對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;
當然,我這裡其實挖掘的不夠徹底,我只是定位到了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>
核心程式碼在此:
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脫離文件流即可
結語
依舊這句話,問題的定位才是難點,若能定位一個問題,其解決方案往往是分分鐘的事情......
這裡記錄這些奇怪的知識點,以便今後查閱,也希望對各位有所幫助!