JavaScript優(yōu)化以及前段開發(fā)小技巧
一、網(wǎng)絡(luò)優(yōu)化
YSlow有23條規(guī)則,中文可以參考這里。這幾十條規(guī)則最主要是在做消除或減少不必要的網(wǎng)絡(luò)延遲,將需要傳輸?shù)臄?shù)據(jù)壓縮至最少。
1)合并壓縮CSS、JavaScript、圖片,靜態(tài)資源CDN緩存
通過構(gòu)建工具Gulp,可以在開發(fā)的時(shí)候就將合并壓縮的事情一起做掉。
之所以要做合并壓縮是因?yàn)椋篐TTP 1.x不允許一個(gè)連接上的多個(gè)響應(yīng)數(shù)據(jù)交錯(cuò)到達(dá)(多路復(fù)用),因而一個(gè)響應(yīng)必須完全返回后,下一個(gè)響應(yīng)才會開始傳輸。
也就是說即使客戶端同時(shí)發(fā)送了兩個(gè)請求,而且CSS資源先準(zhǔn)備就緒,服務(wù)器也會先發(fā)送HTML響應(yīng),然后再交付CSS。
使用CDN是為了讓用戶訪問的時(shí)候能用最近的資源,減少來回傳輸時(shí)間。
HTTP2.0改進(jìn)了HTTP1.x很多方面。
2)CSS放頂部,JavaScript放底部
CSS可以并行下載,而JavaScript加載之后會造成阻塞。
但凡事還是會有例外,如果把行內(nèi)腳本放在樣式表之后,會明顯地延遲資源的下載(結(jié)果是樣式表下載完成并且行內(nèi)腳本執(zhí)行完畢時(shí),后續(xù)資源才能開始下載)。
這是因?yàn)樾袃?nèi)腳本可能含有依賴于樣式表中樣式的代碼,比如document.getElementsByClassName()。
<head> <link rel="stylesheet" href="css/all-normal.css" type="text/css" /> </head> <body> <div id="content"></div> <script> var content = ''; for(i=1; i<1000000; i++) content += '寫入頁面'; document.getElementById('content').innerHTML = content; </script> <img src="images/ui.png" /> </body>
下面通過Chrome的工具查看下:
3)優(yōu)化DNS解析,減少重定向
在做一個(gè)“女神評選活動”的時(shí)候,需要在微信中訪問能夠獲取用戶的openid,微信獲取用戶基本信息是需要經(jīng)過幾個(gè)步驟的:
先獲取code,再通過code獲取openid,最后再跳轉(zhuǎn)訪問靜態(tài)頁面。
由于公司將業(yè)務(wù)分成了多個(gè)小組,所以短短的三步其實(shí)需要三個(gè)小組配合,需要重定向多個(gè)域名。
下圖是未優(yōu)化前的瀑布圖,但不是最壞情況,有時(shí)候訪問到靜態(tài)頁面需要經(jīng)過10多秒,完全不能接受,下圖中會跳轉(zhuǎn)4個(gè)域名:
后面不跳index那個(gè)域名,直接跳轉(zhuǎn)到微信操作域名,減少一個(gè)域名的跳轉(zhuǎn),各小組代碼再做優(yōu)化,但效果還是不理想,僅僅快了幾秒。
最后發(fā)現(xiàn)其實(shí)是在與微信的服務(wù)器做交互的時(shí)候,DNS解析花了太多時(shí)間!不得已,在服務(wù)器的host中添加一條記錄,直接通過IP指向。
下圖是最終優(yōu)化結(jié)果,雖然達(dá)不到秒開,但至少可以接受了:
二、JavaScript優(yōu)化
1)圖片預(yù)加載
在做一個(gè)“秋名山活動”的時(shí)候,使用了圖片預(yù)加載。這個(gè)活動中有120多張圖片。
流程很簡單,就是答題,最后給評論結(jié)果,再分享出去。
如果一下子加載那么多圖片,一定是愚蠢的想法,最后決定,在頁面載入的時(shí)候先加載一些通用圖片。
在答題的時(shí)候當(dāng)前頁面,預(yù)先加載后面頁面中的圖片,防止訪問頁面的時(shí)候直接不展示圖片,圖片也做了適當(dāng)?shù)暮喜ⅰ?/p>
將網(wǎng)站地址放在gtmetrix.com測試,下面是最終的瀑布圖,可以發(fā)現(xiàn)圖片都在其他靜態(tài)資源的后面,這樣能盡早的展現(xiàn)頁面給用戶:
優(yōu)化還遠(yuǎn)遠(yuǎn)沒有結(jié)束,在Chrome中分別模擬了good 2G、good 3G以及4G后,有結(jié)果的情況并不理想。
good 2G:
good 3G:
4G:
還有很大的優(yōu)化空間可以做,關(guān)于這個(gè)預(yù)加載的原理,可以參考《圖片預(yù)加載與懶加載》
2)減少分支
在寫業(yè)務(wù)邏輯的時(shí)候,經(jīng)常會用到if else,switch之類的邏輯判斷,如果每次都做這么多判斷,很容易影響性能。
所以可以通過多種方式來避免過多的判斷。
1. 惰性模式
這是在看《JavaScript設(shè)計(jì)模式》的時(shí)候看到的。
減少每次代碼執(zhí)行時(shí)的重復(fù)性分支判斷,通過對對象重定義來屏蔽原對象中的分支判斷。
惰性模式分為兩種:第一種文件加載后立即執(zhí)行對象方法來重定義,第二種是當(dāng)?shù)谝淮问褂梅椒▽ο髸r(shí)來重定義。
公司有個(gè)頁面要提供給第三方APP,但是最終發(fā)現(xiàn)第三方APP不能使用localStorage緩存,最終只得做兼容的方式。
但為了避免每次引用方法的時(shí)候都做判斷,就使用加載后立即重定義:
var getFn = function() { if (sore.enabled) return sore.get; return cookie.get; }(); var setFn = function() { if (sore.enabled) return sore.set; return cookie.set; }();
2. 建立映射關(guān)系
頁面中經(jīng)常需要彈出框提示,后面就自己做了一個(gè),但彈出框會有很多款式。
如果用簡單工廠模式創(chuàng)建的話,免不了switch分支判斷,后面就直接用賦不同的key,還能緩存起來,只初始化一次。
/** * 彈出框單例模式 */ var factories = {}; var DialogFactory = function(type, options) { if (factories[type]) return factories[type]; return factories[type] = new iDialog(options); }; /** * 提示框 */ var Alert = function(content, options) { var d = DialogFactory('alert', options); //其他邏輯省略 return d; }; /** * 確認(rèn)框 */ var Confirm = function(content, options) { var d = DialogFactory('confirm', options); //其他邏輯省略 return d; };
3)第三方代碼異步加載
第三方代碼,例如百度統(tǒng)計(jì)、微信SDK等,這些完全可以在將業(yè)務(wù)資源加載完后再添加。
/** * 百度統(tǒng)計(jì)設(shè)置 */ util.baidu = function(key) { global._hmt = global._hmt || []; (function() { var hm = document.createElement("script"); hm.src = "http://#/hm.js?" + key; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); };
4)cookie與localStorage緩存
有了緩存后,就能減少與服務(wù)器的通信,在本地操作。
公司有個(gè)查違章的業(yè)務(wù),在本地添加好車輛后,再次進(jìn)入頁面的時(shí)候就需要能直接選擇事先添加好的車輛。
最理想的方式就是添加好后,就在本地緩存起來,下次進(jìn)入直接調(diào)取緩存。
我會優(yōu)先使用localStorage,下面的表格就是對比:
cookie
localStorage
數(shù)據(jù)生命周期
可設(shè)置失效時(shí)間除非被清除,否則永久保存
數(shù)據(jù)大
大約4KB 大約5M
與服務(wù)器通信
每次都會攜帶在HTTP頭中,如果使用cookie保存過多數(shù)據(jù)會帶來性能問題
不參與和服務(wù)器的通信
本地存儲,之前的歷史大概如下圖所示:
localStorage在瀏覽器兼容方面,IE8居然也支持了。
5)事件委托
使用事件委托技術(shù)能讓你避免對特定的每個(gè)節(jié)點(diǎn)添加事件監(jiān)聽器。
事件監(jiān)聽器是被添加到它們的父元素上,通過事件冒泡,觸發(fā)執(zhí)行。
在開發(fā)的時(shí)候,經(jīng)常會出現(xiàn)動態(tài)添加元素的情況。
如果每次都重新綁定一次事件,那會有很多多余操作,而綁定在此元素的父級,就只需綁定一次即可。
document.getElementById('ul').onclick = function(e) { var e = e || window.event, tar = e.target || e.srcElement; if (tar.nodeName.toLowerCase() == 'li') { tar.style.background = 'black'; } }6)節(jié)流與去抖動
節(jié)流(throttle):預(yù)先設(shè)定一個(gè)執(zhí)行周期,當(dāng)調(diào)用動作的時(shí)刻大于等于執(zhí)行周期則執(zhí)行該動作,然后進(jìn)入下一個(gè)新周期。
例如mousemove 事件、window對象的resize和scroll事件。
去抖動(debounce):當(dāng)調(diào)用動作n毫秒后,才會執(zhí)行該動作,若在這n毫秒內(nèi)又調(diào)用此動作則將重新計(jì)算執(zhí)行時(shí)間。
例如文本輸入keydown 事件,keyup 事件,做autocomplete等。
節(jié)流與去抖動最大的不同的地方就是在計(jì)算最后執(zhí)行時(shí)間的方式上。著名的開源工具庫underscore中有內(nèi)置了兩個(gè)方法。
在做公司內(nèi)部的一個(gè)系統(tǒng)的時(shí)候,需要方希望在左右滾動表格的時(shí)候,能將第一列固定在最左邊,方便查看。
為了讓操作能更流暢,我再這里用了節(jié)流,有些瀏覽器會出現(xiàn)卡頓,就得需要增加周期時(shí)間。
三、小技巧
1)在手機(jī)中打印變量
在移動頁面的時(shí)候經(jīng)常需要調(diào)試字段,又不能用console.log,每次alert的話,碰到對象就看不到內(nèi)容了。
只能自己寫個(gè)小方法來打印出來,JSON.stringify,通過這個(gè)方法能夠方便的實(shí)現(xiàn)功能。
var print = function(obj, space) { space = space || 4; var html = JSON.stringify(obj, null, space); html = html.replace(/\n/g, '<br>').replace(/\s/g, ' '); var pre = document.createElement('pre'); var div = document.createElement('code'); pre.style.cssText = 'border:1px solid #000;padding:10px;background:#FFF;margin-bottom:20px;'; div.innerHTML = html; pre.appendChild(div); var body = document.querySelector('body'); body.insertBefore(pre, body.children[0]); }; print({a:1, b:'demo', c:{text:'content'}});
2)chrome插件JSON-handle
服務(wù)器返回的很多都是JSON格式的數(shù)據(jù),通常寫好后給你個(gè)接口,順便給你幾個(gè)demo參數(shù)。
在瀏覽器中打開后,就是一串字符串,但要給人看的話,就得格式化一下了,這個(gè)插件就是用來讓人看的。
相關(guān)文章
Javascript中call,apply,bind方法的詳解與總結(jié)
本文主要Javascript中call,apply,bind方法的進(jìn)行全面分析,并在文章結(jié)尾對call,apply,bind方法的聯(lián)系和區(qū)別做了總結(jié),具有很好的參考價(jià)值,需要的朋友一起來看下吧2016-12-12網(wǎng)頁中JS函數(shù)自動執(zhí)行常用三種方法
這篇文章主要為大家詳細(xì)介紹了網(wǎng)頁中JS函數(shù)自動執(zhí)行常用三種方法,感興趣的小伙伴們可以參考一下2016-03-03javascript運(yùn)行機(jī)制之執(zhí)行順序理解
這篇文章主要介紹了javascript運(yùn)行機(jī)制之執(zhí)行順序理解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08腳本吧 - 幻宇工作室用到j(luò)s,超強(qiáng)推薦expand.js
腳本吧 - 幻宇工作室用到j(luò)s,超強(qiáng)推薦expand.js...2006-12-12