原文鏈接:前端性能優(yōu)化最佳實(shí)踐版權(quán)所有宣赔,轉(zhuǎn)載時(shí)請(qǐng)注明出處,違者必究宿崭。
注明出處格式:前端開(kāi)發(fā)博客 (http://caibaojian.com/webfront-practice.html)
如今瀏覽器能夠?qū)崿F(xiàn)的特性越來(lái)越多,并且網(wǎng)絡(luò)逐漸向移動(dòng)設(shè)備轉(zhuǎn)移,使我們的前端代碼更加緊湊污它,如何優(yōu)化,就變得越來(lái)越重要了。開(kāi)發(fā)人員普遍會(huì)將他們的代碼習(xí)慣優(yōu)先于用戶體驗(yàn)衫贬。但是很多很小的改變可以讓用戶體驗(yàn)有個(gè)飛躍提升德澈,所以任何一點(diǎn)兒小小的優(yōu)化都會(huì)提升你網(wǎng)站的性能。前端給力的地方是可以有許多種簡(jiǎn)單的策略和代碼習(xí)慣讓我們可以保證最理想的前端性能固惯。我們這個(gè)系列的主題就是要告訴你一些前端性能優(yōu)化的最佳實(shí)踐梆造,只需要一分鐘,就可以優(yōu)化你現(xiàn)有的代碼葬毫。(本文內(nèi)容來(lái)自極客標(biāo)簽)
最佳實(shí)踐1:使用DocumentFragments或innerHTML取代復(fù)雜的元素注入
DOM操作在瀏覽器上是要付稅的镇辉。盡管性能提升是在瀏覽器,DOM很慢贴捡,如果你沒(méi)有注意到忽肛,你可能會(huì)察覺(jué)瀏覽器運(yùn)行非常的慢。這就是為什么減少創(chuàng)建集中的DOM節(jié)點(diǎn)以及快速注入是那么的重要了±谜現(xiàn)在假設(shè)我們頁(yè)面中有一個(gè)元素屹逛,調(diào)用AJAX獲取JSON列表,然后使用javascript更新元素內(nèi)容汛骂。通常罕模,程序員會(huì)這么寫:
var list = document.querySelector('ul');
ajaxResult.items.forEach(function(item) {
// 創(chuàng)建元素
var li = document.createElement('li');
li.innerHTML = item.text;
//元素常規(guī)操作,例如添加class帘瞭,更改屬性attribute淑掌,添加事件監(jiān)聽(tīng)等
// 迅速將元素注入父級(jí)中
list.apppendChild(li);
});
上面的代碼其實(shí)是一個(gè)錯(cuò)誤的寫法,將元素帶著對(duì)每一個(gè)列表的DOM操作一起移植是非常慢的图张。如果你真的想要 使用document.createElement锋拖,并且將對(duì)象當(dāng)做節(jié)點(diǎn)來(lái)處理,那么考慮到性能問(wèn)題祸轮,你應(yīng)該使用DocumentFragement兽埃。
DocumentFragement 是一組子節(jié)點(diǎn)的“虛擬存儲(chǔ)”,并且它沒(méi)有父標(biāo)簽适袜。在我們的例子中柄错,將DocumentFragement想象成看不見(jiàn)的元素,在 DOM外苦酱,一直保管著你的子節(jié)點(diǎn)售貌,直到他們被注入DOM中。那么疫萤,原來(lái)的代碼就可以用DocumentFragment優(yōu)化一下:
var frag = document.createDocumentFragment();
ajaxResult.items.forEach(function(item) {
// 創(chuàng)建元素
var li = document.createElement('li');
li.innerHTML = item.text;
//元素常規(guī)操作
// 例如添加class颂跨,更改屬性attribute,添加事件監(jiān)聽(tīng)扯饶,添加子節(jié)點(diǎn)等
// 將元素添加到碎片中
frag.appendChild(li);
});
// 最后將所有的列表對(duì)象通過(guò)DocumentFragment集中注入DOM
document.querySelector('ul').appendChild(frag);
為DocumentFragment追加子元素恒削,然后再將這個(gè)DocumentFragment加到父列表中池颈,這一系列操作僅僅是一個(gè)DOM操作,因此它比起集中注入要快很多钓丰。
如果你不需要將列表對(duì)象當(dāng)做節(jié)點(diǎn)來(lái)操作躯砰,更好的方法是用字符串構(gòu)建html內(nèi)容:
var htmlStr = '';
ajaxResult.items.forEach(function(item) {
// 構(gòu)建包含HTML頁(yè)面內(nèi)容的字符串
htmlStr += '' + item.text + '';
});
// 通過(guò)innerHTML設(shè)定ul內(nèi)容
document.querySelector('ul').innerHTML = htmlStr;
這當(dāng)中也只有一個(gè)DOM操作,并且比起DocumentFragment代碼量更少携丁。在任何情況下琢歇,這兩種方法都比在每一次迭代中將元素注入DOM更高效。
通常梦鉴,開(kāi)發(fā)人員會(huì)在有用戶交互參與的地方添加事件李茫,而往往這種事件會(huì)被頻繁觸發(fā)。想象一下窗口的resize事件或者是一個(gè)元素的onmouseover事件 - 他們觸發(fā)時(shí)肥橙,執(zhí)行的非常迅速涌矢,并且觸發(fā)很多次。如果你的回調(diào)過(guò)重快骗,你可能使瀏覽器死掉娜庇。這就是為什么我們要引入防抖。
防抖可以限制一個(gè)方法在一定時(shí)間內(nèi)執(zhí)行的次數(shù)方篮。以下代碼是個(gè)防抖示例:
// 取自 UnderscoreJS 實(shí)用框架
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
// 添加resize的回調(diào)函數(shù)名秀,但是只允許它每300毫秒執(zhí)行一次
window.addEventListener('resize', debounce(function(event) {
// 這里寫resize過(guò)程
}, 300));
debounce方法返回一個(gè)方法,用來(lái)包住你的回調(diào)函數(shù)藕溅,限制他的執(zhí)行頻率匕得。使用這個(gè)防抖方法,就可以讓你寫的頻繁回調(diào)的方法不會(huì)妨礙用戶的瀏覽器巾表!
最佳實(shí)踐3:網(wǎng)絡(luò)存儲(chǔ)的靜態(tài)緩存和非必要內(nèi)容優(yōu)化
webStorage的API曾經(jīng)是Cookie API一個(gè)顯著的進(jìn)步汁掠,并且為開(kāi)發(fā)者使用了很多年了。這個(gè)API是合理的集币,更大存儲(chǔ)量的考阱,而且是更為健全理智的。一種策略是去使用Session存儲(chǔ)來(lái)存 儲(chǔ)非必要的鞠苟,更為靜態(tài)的內(nèi)容乞榨,例如側(cè)邊欄的HTML內(nèi)容,從Ajax加載進(jìn)來(lái)的文章內(nèi)容当娱,或者一些其他的各種各樣的片斷吃既,是我們只想請(qǐng)求一次的。我們可以使用JavaScript編寫一段代碼跨细,利用Web Storage使這些內(nèi)容加載更加簡(jiǎn)單:
define(function() {
var cacheObj = window.sessionStorage || {
getItem: function(key) {
return this[key];
},
setItem: function(key, value) {
this[key] = value;
}
};
return {
get: function(key) {
return this.isFresh(key);
},
set: function(key, value, minutes) {
var expDate = new Date();
expDate.setMinutes(expDate.getMinutes() + (minutes || 0));
try {
cacheObj.setItem(key, JSON.stringify({
value: value,
expires: expDate.getTime()
}));
}
catch(e) { }
},
isFresh: function(key) {
// 返回值或者返回false
var item;
try {
item = JSON.parse(cacheObj.getItem(key));
}
catch(e) {}
if(!item) return false;
// 日期算法
return new Date().getTime() > item.expires ? false : item.value;
}
}
});
這個(gè)工具提供了一個(gè)基礎(chǔ)的get和set方法鹦倚,同isFresh方法一樣,保證了存儲(chǔ)的數(shù)據(jù)不會(huì)過(guò)期冀惭。調(diào)用方法也非常簡(jiǎn)單:
require(['storage'], function(storage) {
var content = storage.get('sidebarContent');
if(!content) {
// Do an AJAX request to get the sidebar content
// ... and then store returned content for an hour
storage.set('sidebarContent', content, 60);
}
});
現(xiàn)在同樣的內(nèi)容不會(huì)被重復(fù)請(qǐng)求震叙,你的應(yīng)用運(yùn)行的更加有效愤诱。花一點(diǎn)兒時(shí)間捐友,看看你的網(wǎng)站設(shè)計(jì),將那些不會(huì)變化溃槐,但是會(huì)被不斷請(qǐng)求的內(nèi)容挑出來(lái)匣砖,你可以使用Web Storage工具來(lái)提升你網(wǎng)站的性能。
RequireJS已經(jīng)迎來(lái)了異步加載和AMD格式的巨大浪潮猴鲫。XMLHttpRequest(該對(duì)象可以調(diào)用AJAX)使得資源的異步加載變得流行起來(lái),它允許無(wú)阻塞資源加載谣殊,并且使 onload 啟動(dòng)更快拂共,允許頁(yè)面內(nèi)容加載,而不需要刷新頁(yè)面姻几。我所用的異步加載器是John Hann的curl宜狐。curl加載器是基本的異步加載器,可以被配置蛇捌,擁有很好的插件抚恒。以下是一小段curl的代碼:
// 基本使用:? 加載一部分AMD格式的模塊
curl(['social', 'dom'], function(social, dom) {
dom.setElementContent('.social-container', social.loadWidgets());
});
// 定義一個(gè)使用Google Analytics的模塊,該模塊是非AMD格式的
define(["js!//google-analytics.com/ga.js"], function() {
// Return a simple custom Google Analytics controller
return {
trackPageView: function(href) {
_gaq.push(["_trackPageview", url]);
},
trackEvent: function(eventName, href) {
_gaq.push(["_trackEvent", "Interactions", eventName, "", href || window.location, true]);
}
};
});
// 加載一個(gè)不帶回調(diào)方法的非AMD的js文件
curl(['js!//somesite.com/widgets.js']);
// 將JavaScript和CSS文件作為模塊加載
curl(['js!libs/prism/prism.js', 'css!libs/prism/prism.css'], function() {
Prism.highlightAll();
});
// 加載一個(gè)AJAX請(qǐng)求的URL
curl(['text!sidebar.php', 'storage', 'dom'], function(content, storage, dom) {
storage.set('sidebar', content, 60);
dom.setElementContent('.sidebar', content);
});
你可能早就了解络拌,異步加載可以大大提高萬(wàn)展速度俭驮,但是我想在此說(shuō)明的是,你要使用異步加載春贸!使用了之后你可以看到區(qū)別混萝,更重要的是,你的用戶可以看到區(qū)別萍恕。
當(dāng)你可以根據(jù)頁(yè)面內(nèi)容延遲加載依賴的時(shí)候逸嘀,你就可以體會(huì)到異步加載的好處了。例如允粤,你可以只加載Twitter厘熟,F(xiàn)acebook和Google Plus到應(yīng)用了名為social的CSS樣式的div元素中∥“在加載前檢查是否需要”策略可以為我的用戶節(jié)省好幾KB的莫須有的加載绳姨。
最佳實(shí)踐5:使用Array.prototype.join代替字符串連接
有一種非常簡(jiǎn)單的客戶端優(yōu)化方式,就是用Array.prototype.join代替原有的基本的字符連接的寫法阔挠。在上面的“最佳實(shí)踐1”中飘庄,我在代碼中使用了基本字符連接:
htmlStr += '' + item.text + '';
但是下面這段代碼中,我用了優(yōu)化:
var items = [];
ajaxResult.items.forEach(function(item) {
// 構(gòu)建字符串
items.push('', item.text, '');
});
// 通過(guò)innerHTML設(shè)置列表內(nèi)容
document.querySelector('ul').innerHTML = items.join('');
也許你需要花上一點(diǎn)兒時(shí)間來(lái)看看這個(gè)數(shù)組是做什么用的购撼,但是所有的用戶都從這個(gè)優(yōu)化中受益匪淺跪削。
最佳實(shí)踐6:盡可能使用CSS動(dòng)畫
網(wǎng)站設(shè)計(jì)對(duì)美觀特性和可配置元素動(dòng)畫的大量需求谴仙,使得一些JavaScript類庫(kù),如jQuery碾盐,MooTools大量的被使用晃跺。盡管現(xiàn)在瀏覽器支持CSS的transformation和keyframe所做的動(dòng)畫,現(xiàn)在仍有很多人使用JavaScript制作動(dòng)畫效果毫玖,但是實(shí)際上使用CSS動(dòng)畫比起JavaScript驅(qū)動(dòng)的動(dòng)畫效率更高掀虎。CSS動(dòng)畫同時(shí)需要更少的代碼。很多的CSS動(dòng)畫是用GPU處理的付枫,因此動(dòng)畫本身很流暢烹玉,當(dāng)然你可以使用下面這個(gè)簡(jiǎn)單的CSS強(qiáng)制使你的硬件加速:
. myAnimation {
animation : someAnimation 1s;
transform : translate3d(0, 0, 0); /* 強(qiáng)制硬件加速 */
}
tansform:transform(0,0,0)在不會(huì)影響其他動(dòng)畫的同時(shí)將通話送入硬件加速。在不支持CSS動(dòng)畫的情況下(IE8及以下版本的瀏覽器)阐滩,你可以引入JavaScript動(dòng)畫邏輯:
< !--[if 低于IE8版本] >
< script src="http://code.jquery.com/jquery-1.9.1.min.js" >< / script >
< script src="/js/ie-animations.js">< / script >
< ! [endif]-- >
在上例中二打,ie-animations.JS文件必須包含你自定義的jQuery代碼,用于當(dāng)CSS動(dòng)畫在早期IE中不被支持的情況下掂榔,來(lái)替代CSS動(dòng)畫完成動(dòng)畫效果继效。完美的通過(guò)CSS動(dòng)畫來(lái)優(yōu)化動(dòng)畫,通過(guò)JavaScript來(lái)支持全局動(dòng)畫效果装获。
想象一下莲趣,如果你有一個(gè)無(wú)序列表,里面有一堆
元素饱溢,每一個(gè)
元素都會(huì)在點(diǎn)擊的時(shí)候觸發(fā)一個(gè)行為喧伞。這個(gè)時(shí)候,你通常會(huì)在每一個(gè)元素上添加一個(gè)事件監(jiān)聽(tīng)绩郎,但是如果當(dāng)這個(gè)元素或者你添加了監(jiān)聽(tīng)的這個(gè)對(duì)象會(huì)被頻繁的移除添加呢潘鲫?這個(gè)時(shí)候,你在移除添加元素的同時(shí)需要處理事件監(jiān)聽(tīng)的移除和添加肋杖。這個(gè)時(shí)候溉仑,我們就需要引入事件委托了。事件委托是在父級(jí)元素上添加一個(gè)事件監(jiān)聽(tīng)状植,來(lái)替代在每一個(gè)子元素上添加事件監(jiān)聽(tīng)浊竟。當(dāng)事件被觸發(fā)時(shí),event.target會(huì)評(píng)估相應(yīng)的措施是否需要被執(zhí)行津畸。下面我們給出了一個(gè)簡(jiǎn)單的例子:
// 獲取元素,添加事件監(jiān)聽(tīng)
document.querySelector('#parent-list').addEventListener('click', function(e) {
// e.target 是一個(gè)被點(diǎn)擊的元素!
// 如果它是一個(gè)列表元素
if(e.target && e.target.tagName == 'LI') {
// 我們找到了這個(gè)元素肉拓,對(duì)他的操作可以寫在這里后频。
}
});
上面的例子是不可思議的簡(jiǎn)單,當(dāng)事件發(fā)生的時(shí)候,它沒(méi)有輪詢父節(jié)點(diǎn)去尋找匹配的元素或選擇器卑惜,且它不支持基于選擇器的查詢(例如用class name膏执,或者id來(lái)查詢)。所有的JavaScript框架提供了委托選擇器匹配露久。重點(diǎn)是更米,你避免了為每一個(gè)元素加載事件監(jiān)聽(tīng),而是在父元素上加一個(gè)事件監(jiān)聽(tīng)毫痕。這樣大大的增加了效率征峦,并且減少了很多維護(hù)!
提升頁(yè)面大小的效率镇草,不僅僅是取決于使用精靈或是壓縮代碼,給定頁(yè)面的請(qǐng)求數(shù)量在前端性能中也占有了很不小的重量瘤旨。減少請(qǐng)求可以讓你的網(wǎng)站加載更快梯啤,而其中一種減少頁(yè)面請(qǐng)求的方法就是用Data URI代替圖片的src屬性:
<? img src = "/images/logo.png" alt = "前端性能優(yōu)化最佳實(shí)踐" /? >
< img src = "data: image/jpeg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fH ...." / >
<-- 范例:? http://davidwalsh.name/demo/data-uri-php.php -->
當(dāng)然頁(yè)面大小會(huì)增加(如果你的服務(wù)器使用適當(dāng)?shù)膅zip內(nèi)容,這個(gè)增加會(huì)很写嬲堋)因宇,但是你減少了潛在的請(qǐng)求,同時(shí)也在過(guò)程中減少了服務(wù)器請(qǐng)求的數(shù)量∷钔担現(xiàn)在大多數(shù)瀏覽器都支持Data URI察滑,在CSS中的背景骨片也可以使用Data URI,因此這個(gè)策略現(xiàn)在已經(jīng)可以在應(yīng)用層級(jí)修肠,廣泛應(yīng)用贺辰。
直到CSS @supports被廣泛支持,CSS媒體查詢的使用接近于CSS中寫邏輯控制嵌施。我們經(jīng)常用CSS媒體查詢來(lái)根據(jù)設(shè)備調(diào)整CSS屬性(通常根據(jù)屏幕寬度調(diào)整CSS屬性)饲化,例如根據(jù)不同的屏幕寬度來(lái)設(shè)置不同的元素寬度或者是懸浮位置。那么我們?yōu)槭裁床挥眠@種方式來(lái)改變背景圖片呢吗伤?
/* 默認(rèn)是為桌面應(yīng)用加載圖片 */
.someElement { background-image: url(sunset.jpg); }
@media only screen and (max-width : 1024px) {
.someElement { background-image: url(sunset-small.jpg); }
}
上面的代碼片段是為手機(jī)設(shè)備或是類似的移動(dòng)設(shè)備加載一個(gè)較小尺寸的圖片吃靠,特別是需要一個(gè)特別小的圖片時(shí)(例如圖片的大小幾乎不可視)。
最佳實(shí)踐10:使用索引對(duì)象
這一篇足淆,我們將講講使用索引對(duì)象檢索代替遍歷數(shù)組巢块,提高遍歷速度。AJAX和JSON一個(gè)最常見(jiàn)的使用案例是接收包含一組對(duì)象的數(shù)組巧号,然后從這組數(shù)組中根據(jù)給定的值搜索對(duì)象族奢。讓我們看一個(gè)簡(jiǎn)單的例子,下面這個(gè)例子中丹鸿,你從用戶接收一個(gè)數(shù)組歹鱼,然后你可以根據(jù)username的值來(lái)搜索用戶對(duì)象:
function getUser(desiredUsername) {
var searchResult = ajaxResult.users.filter(function(user) {
return user.username == desiredUsername;
});
return searchResult.length ? searchResult[0] : false;
}
// 根據(jù)用戶名獲取用戶
var davidwalsh = getUser("davidwalsh");
// 根據(jù)用戶名獲取另一個(gè)用戶.
var techpro = getuser("tech-pro");
上面這段代碼可以運(yùn)行,但是并不是很有效卜高,當(dāng)我們想要獲取一個(gè)用戶時(shí)弥姻,我們就要遍歷一次數(shù)組南片。那么更好的方法是創(chuàng)建一個(gè)新的對(duì)象,對(duì)每一個(gè)唯一的值建立一個(gè)索引庭敦,在上面這個(gè)例子中疼进,用username作為索引,這個(gè)數(shù)組對(duì)象可以寫成:
var userStore = {};
ajaxResult.users.forEach(function(user) {
userStore[user.username] = user;
});
現(xiàn)在當(dāng)你想要找一個(gè)用戶對(duì)象時(shí)秧廉,我們可以直接通過(guò)索引找到這個(gè)對(duì)象:
var davidwalsh = userStore.davidwalsh;
var techpro = userStore["tech-pro"];
這樣的代碼寫起來(lái)更好一些伞广,也很簡(jiǎn)便,通過(guò)索引搜索比起遍歷整個(gè)數(shù)組更加快捷疼电。
這一篇中嚼锄,我們要說(shuō)如何控制DOM的大小,來(lái)優(yōu)化前端性能蔽豺。DOM很慢是眾所周知的区丑,使得網(wǎng)站變慢的罪魁禍?zhǔn)资谴罅康腄OM。想象一下修陡,假如你有一個(gè)有著上千節(jié)點(diǎn)的DOM沧侥,在想象一下,使用querySelectorAll或者getElementByTagName魄鸦,或者是其他以DOM為中心的搜索方式來(lái)搜索一個(gè)節(jié)點(diǎn)宴杀,即使是使用內(nèi)置方法,這也將是一個(gè)非常費(fèi)力的過(guò)程拾因。你要知道旺罢,多余的DOM節(jié)點(diǎn)會(huì)使其他的實(shí)用程序也變慢的。
我見(jiàn)過(guò)的一種情況绢记,DOM的大小悄然增加主经,是在一個(gè)AJAX網(wǎng)站,它將所有的頁(yè)面都存在了DOM中庭惜,當(dāng)一個(gè)新的頁(yè)面通過(guò)AJAX被加載時(shí)罩驻,舊的頁(yè)面就會(huì)被存入隱藏的DOM節(jié)點(diǎn)。對(duì)于DOM的速度护赊,將有災(zāi)難性的降低惠遏,特別是當(dāng)一個(gè)頁(yè)面是動(dòng)態(tài)加載的。所以你需要一種更好的方法骏啰。
在這種情況下节吮,當(dāng)頁(yè)面是通過(guò)AJAX加載的,并且以前的頁(yè)面是存儲(chǔ)在客戶端的判耕,最好的方法就是將內(nèi)容通過(guò)String HTML存儲(chǔ)(將內(nèi)容從DOM中移除)透绩,然后使用事件委托來(lái)避免特定元素事件。這么做的同時(shí),當(dāng)在客戶端緩存內(nèi)容的時(shí)候帚豪,可以避免大量的DOM生成碳竟。
通常控制DOM大小的技巧包括:
使用:before和:after偽元素
延遲加載和呈現(xiàn)內(nèi)容
使用事件委托狸臣,更簡(jiǎn)便的將節(jié)點(diǎn)轉(zhuǎn)換成字符串存儲(chǔ)
簡(jiǎn)單一句話:盡量使你的DOM越小越好莹桅。
最佳實(shí)踐12:在繁重的執(zhí)行上使用Web Workers
這一篇我們將介紹Web Workder,一種可以將繁重操作移到獨(dú)立進(jìn)程的方法烛亦。Web Workders在前段時(shí)間被引入流行的瀏覽器中诈泼,但是好像并沒(méi)有被廣泛應(yīng)用。Web Workers的主要功能是在一般瀏覽器執(zhí)行范圍外執(zhí)行繁重的方法煤禽。它不會(huì)訪問(wèn)DOM铐达,所以你必須傳入方法涉及的節(jié)點(diǎn)。
以下是一段Web Workder的示例代碼:
/* 使用Web Worker */
//? 啟動(dòng)worker
var worker = new Worker("/path/to/web/worker/resource.js");
worker.addEventListener("message", function(event) {
// 我們從web worker獲取信息!
});
// 指導(dǎo)Web Worker工作檬果!
worker.postMessage({ cmd: "processImageData", data: convertImageToDataUri(myImage) });
/*? resource.js就是一個(gè)Web workder */
self.addEventListener("message", function(event) {
var data = event.data;
switch (data.cmd) {
case 'process':
return processImageData(data.imageData);
});
function processImageData(imageData) {
// 對(duì)圖像進(jìn)行操作
// 例如將它改成灰度
return newImageData;
}
以上這段代碼是一個(gè)教你如何使用Web Worker在其他進(jìn)程中做一些繁重工作的簡(jiǎn)單示例瓮孙。它要執(zhí)行的是將一個(gè)圖片從普通顏色轉(zhuǎn)個(gè)灰度,因?yàn)檫@是一個(gè)比較繁重的過(guò)程汁汗,所以你可以將這個(gè)進(jìn)程提交給Web Worker衷畦,使你的瀏覽器負(fù)載不是很大栗涂。Data通過(guò)message事件傳回知牌。
你可以仔細(xì)閱讀以下MDN上關(guān)于Web Workder的使用,也許在你的網(wǎng)站上有一些功能可以移到其他的獨(dú)立進(jìn)程中去執(zhí)行斤程。
最佳實(shí)踐13:鏈接CSS角寸,避免使用@import
有時(shí)候,@import太好用以至于很難抗拒它的誘惑忿墅,但是為了減少令人抓狂的請(qǐng)求扁藕,你必須要拒絕它!最常見(jiàn)的用法是在一個(gè)"main"CSS文件中疚脐,沒(méi)有任何的內(nèi)容亿柑,只有@import規(guī)則。有時(shí)棍弄,多個(gè)@import規(guī)則往往會(huì)造成事件嵌套:
// 主CSS文件(main.css)
@import "reset.css";
@import "structure.css";
@import "tutorials.css";
@import "contact.css";
// 然后在tutorials.css文件中望薄,會(huì)繼續(xù)有@import
@import "document.css";
@import "syntax-highlighter.css";
我們這樣寫CSS文件,在文件中多了兩個(gè)多余鏈接呼畸,因此會(huì)使頁(yè)面加載變慢痕支。SASS可以讀取@import語(yǔ)句,鏈接CSS內(nèi)容到一個(gè)文件中蛮原,減少了多余的請(qǐng)求卧须,控制了CSS文件的大小。
最佳實(shí)踐14:在CSS文件中包含多種介質(zhì)類型
在上面第13個(gè)最佳實(shí)踐中我們說(shuō)過(guò),多個(gè)CSS文件可以通過(guò)@import規(guī)則合并到一起花嘶。但是很多程序員不知道的是笋籽,多種CSS介質(zhì)類型也可以合并到一個(gè)文件中。
/* 以下全部寫在一個(gè)CSS文件中 */
@media screen {
/* 所有默認(rèn)的結(jié)構(gòu)設(shè)計(jì)和元素樣式寫在這里 */
}
@media print {
/* 調(diào)整打印時(shí)的樣式 */
}
@media only screen and (max-width : 1024px) {
/* 使用ipad或者移動(dòng)電話時(shí)的樣式設(shè)定 */
}
對(duì)于文件的大小察绷,什么時(shí)候必須合并介質(zhì)干签,或是什么時(shí)候必須分開(kāi)設(shè)定,CSS并沒(méi)有硬性規(guī)定拆撼,但是我會(huì)比較建議將所有的介質(zhì)合并容劳,除非其中一個(gè)介質(zhì)所占的比例比起其他大了許多。少一個(gè)請(qǐng)求對(duì)于客戶端和服務(wù)器都將輕松不少闸度,而且在大多數(shù)情況下竭贩,附贈(zèng)的介質(zhì)類型相比主屏介質(zhì)類型要相對(duì)小很多。