前端性能優(yōu)化最佳實(shí)踐--轉(zhuǎn)載

原文鏈接:前端性能優(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更高效。

最佳實(shí)踐2:高頻執(zhí)行事件/方法的防抖

通常梦鉴,開(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)站的性能。

最佳實(shí)踐4:使用異步加載昏滴,延遲加載依賴

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)畫效果装获。

最佳實(shí)踐7:使用事件委托

想象一下莲趣,如果你有一個(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ù)!

最佳實(shí)踐8:使用Data URI代替圖片SRC

提升頁(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)用贺辰。

最佳實(shí)踐9:使用媒體查詢加載指定大小的背景圖片

直到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ù)組更加快捷疼电。

最佳實(shí)踐11:控制DOM大小

這一篇中嚼锄,我們要說(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ì)小很多。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末莺禁,一起剝皮案震驚了整個(gè)濱河市留量,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌哟冬,老刑警劉巖楼熄,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異浩峡,居然都是意外死亡可岂,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門翰灾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)缕粹,“玉大人,你說(shuō)我怎么就攤上這事纸淮∑秸叮” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵咽块,是天一觀的道長(zhǎng)绘面。 經(jīng)常有香客問(wèn)我,道長(zhǎng)侈沪,這世上最難降的妖魔是什么揭璃? 我笑而不...
    開(kāi)封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮峭竣,結(jié)果婚禮上塘辅,老公的妹妹穿的比我還像新娘。我一直安慰自己皆撩,他們只是感情好扣墩,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布哲银。 她就那樣靜靜地躺著,像睡著了一般呻惕。 火紅的嫁衣襯著肌膚如雪荆责。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天亚脆,我揣著相機(jī)與錄音做院,去河邊找鬼。 笑死濒持,一個(gè)胖子當(dāng)著我的面吹牛键耕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播柑营,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼屈雄,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了官套?” 一聲冷哼從身側(cè)響起酒奶,我...
    開(kāi)封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎奶赔,沒(méi)想到半個(gè)月后惋嚎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡站刑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年另伍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笛钝。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡质况,死狀恐怖愕宋,靈堂內(nèi)的尸體忽然破棺而出玻靡,到底是詐尸還是另有隱情,我是刑警寧澤中贝,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布囤捻,位于F島的核電站,受9級(jí)特大地震影響邻寿,放射性物質(zhì)發(fā)生泄漏蝎土。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一绣否、第九天 我趴在偏房一處隱蔽的房頂上張望誊涯。 院中可真熱鬧,春花似錦蒜撮、人聲如沸暴构。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)取逾。三九已至耗绿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間砾隅,已是汗流浹背误阻。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留晴埂,地道東北人究反。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像儒洛,于是被迫代替她去往敵國(guó)和親奴紧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容