ASP.NET性能優(yōu)化的15個技巧
譯文【51CTO.com快譯】引言:2018年,加載速度和用戶滿意度仍會是各個Web應(yīng)用所要面對的首要問題。緩慢的加載時間和不佳的互動體驗都可能將客戶推往他處。本文向你提供15個ASP.NET性能優(yōu)化的小技巧。
對于ASP.NET的Web應(yīng)用來說性能一直是非常重要的。各種證據(jù)表明,緩慢的加載時間和不佳的互動體驗都可能將客戶推往他處。即使是那些對于用戶來說別無選擇的內(nèi)部應(yīng)用,他們的滿意度也是會與速度掛鉤的。
我們可以用很多種方法來提高網(wǎng)站的性能。在此,讓我們來看看其中的十五個。
1.量化一切
首先要做的***件事是收集應(yīng)用程序的性能基線。有時候,你的本意是想通過一些修改來提高網(wǎng)站的性能,但是實(shí)際上性能卻被降低了。雖然談不上是個黑盒子,但是對于性能的調(diào)優(yōu),確實(shí)會時常給我們帶來意想不到的效果。因此,量化性能需要有一個全面的對于服務(wù)器、JavaScript和加載效率的衡量。除了手中的秒表,你還需要有諸如Prefix之類的各種性能測試工具(請參見:https://stackify.com/prefix/)。
Prefix能讓你更關(guān)注于低效的查詢,以及大量的JavaScript文件等方面。量化的數(shù)據(jù)會告訴你,對于哪些方面的優(yōu)化能夠真正起到作用。你可以自己生產(chǎn)一張列表,并按照優(yōu)先級進(jìn)行排序。而那些位于列表底部的,則往往是一些重要程度最小、你幾乎可以忽略的方面。
2.先摘下“低垂的水果”
通常情況下,你應(yīng)該優(yōu)先處理上述清單中影響比較大的部分。很明顯,如果你能盡快地向用戶證明性能影響的“痛點(diǎn)”所在,你就能從精神上和資金上獲得更多的優(yōu)化支持,當(dāng)然這也是你不斷進(jìn)行性能調(diào)優(yōu)的動力。比如說:全局性的因素(如JavaScript、CSS、及其同類的加載)都會比單個頁面的修改產(chǎn)生更大的影響。
本文后面介紹的內(nèi)容,將粗略地以影響程度從大到小來依次展開。當(dāng)然,根據(jù)各個網(wǎng)站的差異性,你可以有所取舍地根據(jù)自身情況來予以實(shí)踐。
3.啟用壓縮
HTTP協(xié)議并非是一個特別有效率的協(xié)議。在默認(rèn)情況下,它不會對內(nèi)容進(jìn)行壓縮。雖然有些網(wǎng)絡(luò)資源,比如說圖片已經(jīng)被壓縮了,但是像HTML、CSS和JavaScript通常還是以文本的形式在進(jìn)行傳輸。就算是最古老的瀏覽器也能支持通過gzip的算法來對HTTP內(nèi)容進(jìn)行壓縮,而且gzip大約能夠壓縮HTML文件的三分之二。也就是說:一個100KB的文件被壓縮后最終至多只有33KB,這比例是相當(dāng)驚人的!
與之對應(yīng)的另一個改良算法是Brotli(請參見:https://en.wikipedia.org/wiki/Brotli)。其效果更佳,而且能夠被當(dāng)前大多數(shù)瀏覽器所支持。
4.減少HTTP請求
實(shí)際上,瀏覽器每打開和建立一個與服務(wù)器的連接,都是要“交稅”的。而這個稅收就是以TCP/IP連接的開銷形式來體現(xiàn)的。這個現(xiàn)象在那些具有高延遲、并需要花費(fèi)很長時間才能建立新連接的情況下,就顯得尤為突然?;谶@個客觀事實(shí),為了減少HTTP的請求數(shù)量,瀏覽器應(yīng)該將它們的請求限制在單臺服務(wù)器上,以實(shí)現(xiàn)***程度的優(yōu)化。
延遲與帶寬
我們在優(yōu)化網(wǎng)頁的加載時,理解延遲和帶寬之間的差別是非常必要的。讓我們想象一下:你有20頭驢,你需要從坐落在班芙的一個集散點(diǎn)轉(zhuǎn)移到另一個坐落在大峽谷的集散點(diǎn)。為了讓這些驢子能夠盡快地轉(zhuǎn)移過去,你需要優(yōu)化兩個方面:你一次性能夠轉(zhuǎn)移的驢子的數(shù)量,和單次轉(zhuǎn)移驢子所需要的時間。
帶寬就像是你一次性能夠轉(zhuǎn)移的驢子的數(shù)量。在高帶寬的情況下,你可以一次性將多個驢子放入家畜車進(jìn)行轉(zhuǎn)移。而在低帶寬的情況下,你只能將一頭驢子放在你那2001年產(chǎn)的本田思域的單個座位上進(jìn)行轉(zhuǎn)移。
而延遲則是你從班芙到大峽谷,進(jìn)行單次轉(zhuǎn)移驢子所需要的時間。高延遲意味著沿途有多次延誤,所以減慢了單次的轉(zhuǎn)移時間。而低延遲則意味著你通宵達(dá)旦地一路狂奔,不會在任何旅游景點(diǎn)處停車觀景。因此在理想情況下,你應(yīng)該一次性轉(zhuǎn)移盡可能多的驢子,而且避免沿途上的任何停頓。
封裝
根據(jù)向服務(wù)器請求的資源類型不同,我們可以用幾個不同的方法來降低請求的數(shù)量。對于JavaScript,可用類似webpack、gulp或grunt的工具將各個JavaScript腳本捆綁“串聯(lián)”到一起成為一個單獨(dú)文件。我們也可以使用相同工具里的不同任務(wù),來將CSS文件合并為單一文件。
而對于圖像則有點(diǎn)復(fù)雜。如果你在網(wǎng)站上使用了許多小的圖像,那么就可以使用CSS Spriting的技術(shù)。比如說:我們將所有的圖像合并成單獨(dú)的一個,然后使用CSS的偏移量將圖像進(jìn)行轉(zhuǎn)換,只顯示我們所需要的單個子圖像。還有其他的一些工具,能夠簡化該過程,不過它們都需要人工的干預(yù)。而另一種可選的方法則是使用icon font。
5. 基于SSL的HTTP/2
HTTP/2是HTTP的新版本,它進(jìn)行了許多非常有用的優(yōu)化。首先,在上面提到壓縮方面,它進(jìn)行了擴(kuò)展,同時也包含了各種協(xié)議的包頭。更有趣的是,在與服務(wù)器之間的連接上,它使用一種被稱為“管道”的機(jī)制,來傳輸多個文件。這就意味著:通過合并文件來減少HTTP請求的方式在很大程度上已經(jīng)不必要了,而它的效率則更高。
如今,幾乎每一種瀏覽器都能支持HTTP/2。但頗具諷刺意味的是:在服務(wù)器端的支持上卻有著各種限制。例如:在寫數(shù)據(jù)的時候,Azure的Web應(yīng)用程序就不能支持HTTP/2。
不過,服務(wù)器現(xiàn)在也能夠?qū)W(wǎng)頁上的內(nèi)容做出智能的決策,并在它們被請求之前就主動向下推送資源。因此,如果索引(主)頁面上包含一個JavaScript文件的話,它只有在瀏覽器解析了整個頁面之后才會被發(fā)現(xiàn);而現(xiàn)在的服務(wù)器完全可以根據(jù)指令,在瀏覽器意識到它之前,就主動將該文件傳輸過去。
因為所有支持HTTP2的瀏覽器都能夠提供HTTPS的服務(wù),因此SSL自然也是必需支持的技術(shù)之一。
6.縮減文件尺寸
雖然壓縮對于減少傳輸線路上的數(shù)據(jù)總量來說是一種很好的手段,但是所有的壓縮算法對于發(fā)送HTML、CSS和JavaScript來說都是無損的壓縮方式。這就意味著對compress(x)的結(jié)果進(jìn)行解壓縮--decompress(x)總能得到x。在理解了這一點(diǎn)的基礎(chǔ)上,我們就可以尋求在尺寸上的進(jìn)一步縮減了。舉例而言,如下的JavaScript:
- function doSomething(){
- var size_of_something_to_do = 55;
- for (var counter_of_stuff = 0;
- counter_of_stuff < size_of_something_to_do;
- counter_of_stuff++) {
- size_of_something_to_do--;
- }
- }
它在功能上等同于:
- function doSomething(){var a=55;for(var b=0;b<a;b++){a--;}}
由于變量的作用域是完全私有的,因此空白的占位符就顯得沒有必要了。這個過程被稱為縮減。與壓縮技術(shù)類似,該技術(shù)也可以被應(yīng)用到CSS、甚至是HTML上。
7.優(yōu)先加載CSS
請務(wù)必優(yōu)先加載你網(wǎng)站上的CSS內(nèi)容,而且***放在頁面的頭部。
要理解這個原因,你需要先了解瀏覽器是如何實(shí)現(xiàn)其驚人的瀏覽速度的。在下載頁面的同時,瀏覽器會盡快將其從應(yīng)用程序那里得到的內(nèi)容渲染出來。通常情況下,由于瀏覽器并不知道頁面上的哪些內(nèi)容是無效的,因此它只能像玩猜謎游戲那些做出猜測。
之后,當(dāng)瀏覽器意識到其猜測有誤時,它不得不拋棄之前所做的一切,重新開始渲染。其中導(dǎo)致這些返工的一個原因就是可能要增加新的樣式表。因此,優(yōu)先加載樣式表,就可以避免對已經(jīng)渲染的元素進(jìn)行返工。
8.***加載JavaScript
JavaScript則是CSS的另一面,應(yīng)當(dāng)***被加載。這是因為我們希望頁面能夠被盡可快地渲染出來,而JavaScript則沒必要在一開始就被渲染。用戶通常會花些時間來閱讀頁面的內(nèi)容,以決定下一步做什么。那么這個時間窗口就被用來在后臺加載腳本、和顯示頁面上的交互效果了。
不過,這里需要注意的是:如果你的網(wǎng)站上有大量的JavaScript,例如Angular或React之類的應(yīng)用,那么你可能會發(fā)現(xiàn)***加載JavaScript反而不一定是***的方案。你不妨考慮采用只加載JavaScript的必要部分到bootstrap的應(yīng)用中,并且在后臺加載更多的JavaScript。如果速度對你來說非常重要的話,你甚至可以考慮所謂的同構(gòu)或是通用的應(yīng)用程序。因為在這些應(yīng)用中,各個頁面在服務(wù)器端被渲染,然后JavaScript應(yīng)用被附加到已渲染的HTML中,并予以接管。這些應(yīng)用程序具有在加載的過程中無縫銜接的速度優(yōu)勢。
9.縮小圖片
在理想狀態(tài)下,你的網(wǎng)站根本不會包含任何圖片。通常情況,矢量圖片會比各種真彩圖片要小許多,因此如果使用inline-SVG和CSS的技巧來為你的網(wǎng)頁創(chuàng)建矢量圖的話,效率會非常高。然而事實(shí)上卻不能完全是這樣,因此,你必需進(jìn)行一些縮小圖片的工作。雖然要搞清楚各種正確的編碼設(shè)置著實(shí)不容易,但是我們可以借助像tinypng之類的服務(wù)(請參見https://tinypng.com/)來達(dá)到目標(biāo)。另外,它的logo是一只非??蓯鄣男茇?。
當(dāng)然,也有一些JavaScript構(gòu)建工具的其他插件,可以達(dá)到類似的優(yōu)化效果,請參見:https://www.npmjs.com/package/gulp-image-optimization。
10.檢查你的查詢
各種對象關(guān)系映射(object-relational mappers,ORM)已經(jīng)對開發(fā)人員的生產(chǎn)力起到了提升作用,但它們只是提供了優(yōu)化查詢的一個抽象層。當(dāng)你可能會有N+1個選擇錯誤、或是從服務(wù)器獲取了太多的數(shù)據(jù)時,只有通過Prefix才能夠突顯具體的次數(shù)。你會驚奇地發(fā)現(xiàn)通過使用預(yù)先加載、而非延遲加載,以及檢查各種預(yù)測值,問題就會變得非常容易解決。當(dāng)然,微軟對于優(yōu)化實(shí)體框架(Entity Framework,EF)的各種SQL調(diào)用,也有一些獨(dú)到的建議,請參見:https://msdn.microsoft.com/en-us/library/hh949853(v=vs.113).aspx。
11.緩存你的頁面
通常情況下,你網(wǎng)頁上的數(shù)據(jù)會隨著時間的推移而緩慢發(fā)生變化。比如說:在Stack Overflow(譯者注:它是一個技術(shù)問答網(wǎng)站。用戶可以在該網(wǎng)站上免費(fèi)創(chuàng)建主頁、提交問題、瀏覽問題、索引相關(guān)內(nèi)容。)上的那些熱點(diǎn)問題的頁面會實(shí)時地被更新,但是其數(shù)據(jù)的變化并不夠顯著,不至于觸發(fā)對數(shù)據(jù)庫的重新查詢。因此我們沒有必要去調(diào)整數(shù)據(jù)庫、并對復(fù)雜的頁面進(jìn)行重新渲染,而是可以將該網(wǎng)頁推送到緩存隊列中,并使用這些數(shù)據(jù)來響應(yīng)后續(xù)的請求。
如果你碰巧使用著ASP.NET的MVC緩存,那么一個action的響應(yīng)就應(yīng)該只是簡單地添加單一的屬性到action中。
- [HandleError] public class HomeController : Controller {
- [OutputCache(Duration=10, VaryByParam="none")]
- public ActionResult Index() {
- return View();
- }
- }
如果你所緩存的頁面全部內(nèi)容并非是你都需要的,那么請繼續(xù)往下看第12個技巧。
12.僅緩存頁面的部分內(nèi)容
你可能只想緩存頁面的一部分內(nèi)容; 這被俗稱為甜甜圈孔洞緩存(donut hole caching)。當(dāng)你在同一頁上,既有用戶特有的數(shù)據(jù)、又有一般的數(shù)據(jù)時,這會是一種非常有用的方法。用戶特有數(shù)據(jù)隨著用戶的不同而改變,而頁面上的其余部分則對于所有用戶都是相同的。在MVC 5的應(yīng)用中,這是通過做局部視圖(請參見:https://visualstudiomagazine.com/articles/2017/05/01/doughnut-hole-caching.aspx)來實(shí)現(xiàn)的,并且在MVC的核心,我們會用到緩存標(biāo)簽幫手(請參見:https://www.davepaquette.com/archive/2015/06/03/mvc-6-cache-tag-helper.aspx)。
13.內(nèi)容分發(fā)網(wǎng)絡(luò)(CDN)
全球各處都有非常多的內(nèi)容交付網(wǎng)絡(luò),它們可以通過離你最近的節(jié)點(diǎn),將內(nèi)容高速地傳遞到你的面前。
14.縮小你的庫
如果你正在使用像jQuery之類的庫,那么你可以考慮是否真的會用到它的所有功能,也許你可以去使用一個更小、更有針對性的庫。比如說:Zeptojs就是一個能夠支持jQuery的很多功能、而又更小的庫。其他像jQuery UI的庫,也能為構(gòu)建個性化的包提供刪減過的功能。如果你正在使用Augular的話,那么你在對產(chǎn)品進(jìn)行編譯的時候,就可以像“搖動樹干”一樣,將那些在你的項目中完全用不到的庫去除掉??梢娺@種方式在保留同等功能的情況下,能有效減少傳輸中的數(shù)據(jù)載荷。
15.避免客戶端重定向
***的技巧是避免通過使用客戶端的重定向。重定向勢必添加了額外的服務(wù)器跳轉(zhuǎn)的開銷。而在諸如蜂窩網(wǎng)絡(luò)這樣高延遲的網(wǎng)絡(luò)中則是完全不可取的。相反地,如果使用服務(wù)器端的重定向,則不會增加跳轉(zhuǎn)的開銷。不過,此法對于將用戶重定向到SSL版本的頁面上卻不太有效果。針對這種情況,HTTP嚴(yán)格傳輸安全(HTTP Strict Transport Security,HSTS,請參見:https://www.troyhunt.com/understanding-http-strict-transport/)和預(yù)加載正好能夠提供幫助。只要你將網(wǎng)站加入預(yù)加載列表中,就會被自動重定向到相應(yīng)的SSL版網(wǎng)頁上。
我們希望上述這些技巧能夠有助于提高你的網(wǎng)站性能,以及用戶的滿意度。如果你覺得我們疏漏了任何技巧的話,請留言為我們添磚加瓦。當(dāng)然,你也可以擴(kuò)展性地閱讀一下Matt Watson的《有關(guān)服務(wù)器和客戶端性能的三大Web優(yōu)化技巧》(https://stackify.com/web-performance-optimization/)。
原文標(biāo)題:15 Simple ASP.NET Performance Tuning Tips,作者: Simon Timms
【51CTO譯稿,合作站點(diǎn)轉(zhuǎn)載請注明原文譯者和出處為51CTO.com】