若是你的網站3秒鐘沒有響應,人們就會失去興趣了。爲了知足響應快這個願望,須要一個不一樣的方法在手機上進行分析,設計和測試。css
這篇文章將會對Johan Johansson在2013年4月提出" 怎樣讓你的網站在手機上也很快"的這種理念進行擴展。咱們將提出論證方法來確認人們在手機上與網站的交互方式和之前是不同的,特別是設計也是基於此理念的。咱們的目標不只僅是提升網站性能,並且也要增長客戶收入的。html
咱們將關注手機兩個特性,這兩個特性短時間內也不會有變化:電池容量小,屏幕小。web
手機的通信要用無線電,但手機的電池很小,因此要很是謹慎的用電以防止把電用光。這樣,若是無線電不用的時候就會迅速關掉,這樣就增長了網頁出現的時間。2G和3G無線技術須要2秒鐘來創建HTTP連接。若是我接受「用戶會在3秒後失去興趣」的觀點的話,那咱們的網站只有1秒來響應了。想一想這「黃金般的一秒」吧。算法
最大化利用這「黃金一秒」瀏覽器
在物理世界中,廣告牌和雜誌的內容都是根據媒介的大小和觀看距離來定製的。在數字世界中,一個典型的中檔智能手機擁有幾乎6平方英寸大小的屏幕。15英寸的MacBook Pro電腦屏幕擁有超過100平方英寸的大小。這樣,咱們不只能夠經過減小發送到手機端的內容優化網站性能,並且能夠優化業務流程來提升網站全部者的投資回報。緩存
本文的代碼示例是由.NET提供。我已經在companion article文章中展現了用PHP, Java, C 和Python達到一樣的效果。我在這篇文章的結尾會解釋爲何選用.NET。 性能優化
網站設計者和開發者們經常想固然的認爲用戶應該用高帶寬Wi-Fi和固網來鏈接。響應式網站設計(RWD)強制在不一樣設備上(不論其性能好壞)顯示相同的內容、導航和業務流程,限制了創新。服務器
確保咱們可以容易的進行性能測量,進行用戶行爲監控的基於不一樣設備特性的解決方案以及低帶寬設備網頁訪問優化都須要最大限度的利用這「黃金一秒」。cookie
現實移動帶寬模擬測試是一個必不可少的移動Web性能測試。不少100美圓如下的廉價無線路由都提供了限制帶寬功能,測試僅僅只涉及到了局域網內的客戶端的上行和下行帶寬限制功能。若是路由不支持這個功能話,那麼試試用 DD-WRT(DD-WRT是一個開源升級固件,能夠替代目前主流路由的默認操做系統)來限制帶寬。網絡
我用DD-WRT升級了Linksys E3000路由。路由升級的過程很是簡單,DD-WRT官網上提供了完整的說明。
安裝好DD-WRT後去到QoS菜單,啓用帶寬限制。設置上行和下行帶寬的值,我習慣將下行帶寬設置爲256kbps,上行帶寬設置爲28kbps來模擬移動網絡的平均帶寬。
在「Quality of Service」選項中限定帶寬
如今不管是以Wi-Fi或網線鏈接到路由器的設備的帶寬都被人爲的限制了。咱們能夠監視帶寬實際的使用狀況。
用DD-WRT監視帶寬使用
雖然這種測試方法並無包括隨機的掉線、可變帶寬條件和由信號強弱引發的延遲等狀況,可是比起你在快速、低延遲帶寬下作的其餘測試效果要好。在網站開發初期,這是一個在開發過程當中對Web性能進行非正式測試的簡單的方法,可以確保你在正式測試過程當中不出現任何討厭的問題。
管理顧問 Peter Drucker 曾經說過一句名言:「若是你沒法測量某件事,你就沒法管理它。」
平均屏幕尺寸隨時間的推移的增加狀況
持續根據設備特性(好比無線支持或屏幕大小)對用戶查看的內容進行監控,或多或少將會有助於你識別手機上流行的內容和服務。也許你將看不到任何區別,可是除非你測量過,不然沒法肯定。
一個全球化的快餐特許經營店須要建立針對移動終端的大屏幕互聯網站點的優化版本。在建立第一個針對移動終端優化的互聯網站點以前,執行分析以肯定大屏幕互聯網站點的哪些項是小屏幕設備的用戶能夠訪問的。主菜單、特賣品和分店查找是最受歡迎的,所以建立針對移動設備優化的互聯網站點就集中在這些方面。
工做不能停留在此。接着的分析顯示出分店查找是最受歡迎的。所以再次修改移動設備的主頁以關注分店查找。繼續的監視顯示出多少訪問者選擇其餘選項,而後依此不斷改善地這個互聯網站點,以確保用最簡單可行的方法實現最受歡迎的欄目。
Google Analytics 提供了一些關於設備模型的信息,但它缺少咱們須要基於屏幕尺寸和輸入方法做出明智決定的細節。幸運的是,一個全面的設備檢測庫(DDR)能夠將此信息添加到現有日誌文件中。下面的代碼片斷能夠添加到 .NET網站中,參考51degrees.mobi(可經過 NuGet ) 獲取屏幕的物理尺寸和輸出到一個簡單的CSV文件中。
1
2
3
4
5
6
7
8
9
10
11
12
|
// Write a log file containing the current time, and the screen
// size of the requesting device in inches.
File.AppendAllText(
Path.Combine(
AppDomain.CurrentDomain.BaseDirectory, String.Format(
"App_Data\\Simple_Log_{0:yyyyMMdd}.csv"
,
DateTime.UtcNow)),
String.Format(
"{0:s},{1},{2},{3}\r\n"
,
DateTime.UtcNow,
Request.Path,
Request.Browser[
"ScreenInchesWidth"
],
Request.Browser[
"ScreenInchesHeight"
]));
|
第一行是處理請求的日期和時間。第二行是請求的頁面。最後兩行是設備屏幕的寬度和高度。抓取足夠多的數據和平均屏幕的尺寸大小繪製出了下面的圖表:
比較設備屏幕的平均大小超過20個月
分析能夠縮小到具體的頁面。有關設備的特性,操做系統和瀏覽器也能夠被添加到列中。
相似的代碼可使用PHP、Java、Python和其餘環境語言。
有時,已有的Web頁面不能按照上面的方式修改。在這樣的狀況下,DDR能夠用來執行含有用戶代理的日誌日文的離線分析了。下面的.NET代碼是一個實用的命令行程序,它解析空格分隔的日誌文件,而後計算出日誌所表示的請求以平方英尺爲單位的平均屏幕尺寸。第一個參數是日誌文件的位置,第二個參數是日誌文件裏用戶代理所在列的索引。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
using
System;
using
FiftyOne.Foundation.Mobile.Detection.Binary;
using
System.IO;
namespace
ConsoleApplication
{
class
Program
{
static
void
Main(
string
[] args)
{
// The number of devices read from the log file.
int
count = 0;
// The column in the input file the user agent is held in.
int
column =
int
.Parse(args[1]);
// Screen dimension variables.
double
total = 0, width, height, squareInches;
// Create a provider to determine the device capabilities.
var provider = Reader.Create(
"51Degrees.mobi.dat"
);
// Read each line of the log file provided in argument 0.
// Assume the value at column 8 is the UserAgent string.
using
(var reader = File.OpenText(args[0]))
{
while
(reader.EndOfStream ==
false
)
{
var values = reader.ReadLine().Split(
new
[] {
' '
});
if
(values.Length >= column)
{
// Get the device information based on the UserAgent.
var device = provider.GetDeviceInfo(
values[column - 1].Replace(
"+"
,
" "
));
if
(device !=
null
)
{
// Determine the screen dimensions in inches.
double
.TryParse(
device.GetFirstPropertyValue(
"ScreenInchesWidth"
),
out
width);
double
.TryParse(
device.GetFirstPropertyValue(
"ScreenInchesHeight"
),
out
height);
squareInches = width * height;
// If valid values are available (not a desktop/laptop)
// then add the values to the results.
if
(squareInches > 0)
{
total += squareInches;
count++;
}
}
}
}
}
Console.WriteLine(
"Average screen size '{0:#.00}' square inches from '{1}' devices"
,
total / count,
count);
Console.ReadKey();
}
}
}
|
分析日誌文件很不許確,由於除了用戶代理外的其餘HTTP頭都影響着檢測結果。對Opera Mini和Opera 移動瀏覽器來講尤爲是這樣的。在這兩個瀏覽器裏,第二個HTTP頭,也就是名字爲Device-Stock-UA的頭經常用來提供標準用戶代理裏沒有的有關物理硬件的信息。
監控使得咱們可以將不受歡迎的內容從主頁中刪除,以此提高更重要的內容或相關的內容的性能。刪除的內容應該仍能夠經過二級頁面訪問到——只是不放在首頁,否則的話它們會消耗寶貴的帶寬並下降性能體驗。
那麼,咱們怎樣來建立一個獨立的性能優化的移動網站呢?
我能理解爲何RWD(響應web設計)從用戶界面設計的角度來講頗有意義。對於6平方英寸屏幕和10平方英寸屏幕,以及僅僅是須要進行改動的佈局來講,在內容,導航以及業務流程需求方面能夠徹底一致,這實在是太棒了。
平均設備屏幕尺寸。
可是,在上述條件不爲真或者對性能要求嚴格的時候有一個獨立的移動網站 具備特別的意義。
獨立的移動網站經常表現出一種不良的用戶體驗。經過給網站懲罰賦以較低的搜索引擎等級,Google如今投射出一縷曙光 到這些普通的問題上。問題包括了將每一個桌面頁發送到單獨的移動主頁,重定向到應用下載頁,阻止用戶訪問大屏的網站,對全部帶特定操做系統的設備以相同的方式處理。
這些糟糕的實現讓人對這些概念有一個壞的印象。這裏是一些簡單又正確的作法。
下面的 .NETweb.config片斷將把來自智能手機的第一個請求,重定向到網站上「Smartphone」部分指定的等價頁面。 重要的是,查詢字符串與頁面名字在重定向的過程當中一直保持着。
1
2
3
4
5
6
7
8
9
10
11
12
|
<
redirect
firstRequestOnly
=
"true"
mobileHomePageUrl
=
"~/Mobile/Default.aspx"
timeout
=
"20"
devicesFile
=
"~/App_Data/Devices.dat"
mobilePagesRegex
=
"/(Mobile|Smartphone)/"
>
<
locations
>
<!--Send smartphones to an equivalent version of the original page, preserving the page name and query string.-->
<
location
name
=
"smartphone"
url
=
"~/Smartphone/{0}"
matchExpression
=
"(?<=^\w+://.+/).+"
>
<
add
property
=
"IsSmartphone"
matchExpression
=
"true"
/>
</
location
>
</
locations
>
</
redirect
>
|
在大多數情形,當重定向到替代頁面時,若是願意的話用戶應當能夠返回原始的頁面;或許他們對網站的大屏幕版本更熟悉呢。firstRequestOnly屬性保證了只有來自設備的第一次請求才被重定向。devicesFile屬性是用來對不支持cookies的設備進行跟蹤。timeout屬性控制了在多長時間內該設備被記憶(爲了重定向的目的)。
重定向系統還必須知道哪一個頁面是針對哪一種設備設計的。mobilePagesRegex屬性被應用到請求URLs。若是存在匹配,頁面將不適用重定向。這阻止了無窮重定向的狀況。
locations元素容許配置定義不一樣的地址,以及相關的規則。這個例子將Smartphone目錄插入到原始的URL。查詢字符串和其餘的URL信息在重定向過程當中一直保持。全部影響到請求上下文的信息必須被傳送,以便用戶得到他們指望的內容。
這個簡單的方法使得一個搜索引擎友好的,兼容Google的,移動手機優化的網站,在傳送的過程當中有良好的用戶體驗和優異的性能。這個過程的基礎是DDR,它快速的,一致的,精確的提供了設備的信息。對於改變了移動手機瀏覽器設置到桌面模式的用戶,重定向將不會發生。
雲服務是給網站迅速增長特性的流行方法。可是它們跨越Internet的請求對性能帶來損耗。若是忽略處理時間,咱們觀察到由Amazon Web Service提供的雲服務的數據傳輸有平均200毫秒的延時。
200毫秒是一個黃金秒的20%。所以,仔細考慮一下你使用的雲服務在哪裏,確保它們是異步調用的,以便在等待響應的過程當中其餘處理能繼續下去。它們應該避免關鍵路徑上的活動,例如判別請求設備的信息。
緊隨視頻、圖像以後,CSS和HTML佔據了大量的Web流量。咱們須要優化全部這一切的方法。視頻自己就是就能夠寫一篇文章,因此要等之後再說。
圖像
流行的解決方案是同一張圖像提供三個版本,並且當瀏覽器渲染頁面的時候,使用JavaScript或者CSS選擇最適合請求設備的那張圖象。這是一個好的開始,不過管理同一圖像的不一樣版本倒是很痛苦的;圖像歷來都不是完美優化的,並且這種方法給有限CPU和電池電量的移動設備增長了進行圖像大小調整的負擔。
有一個更好的處理方法是使用圖像優化器。能夠經過Viusal Studio的集成開發環境把52Degrees.mobi的圖像優化器增長到ASP.NET站點。下面的配置將自動增長到web.config裏。
1
2
3
|
<
handlers
>
<
add
name
=
"Image"
verb
=
"GET"
path
=
"P.axd"
type
=
"FiftyOne.Framework.Image.ImageHandler, FiftyOne.Framework"
/>
</
handlers
>
|
上面的處理器告訴互聯網信息服務(IIS)圖像處理器應該處理資源P.axd的任何GET請求。
一旦web.config裏啓用這項,下面的ASP.NET代碼將使用圖像優化器從三種可能的資源-也就是分別爲240,480和640像素寬的圖像中肯定一個圖像。
1
2
3
4
5
|
<
mob:Image
runat
=
"server"
ID
=
"ImageBanner"
CalculateSizeMode
=
"ClientWidth"
Style
=
"clear: both; width: 100%"
>
<
mob:AltImage
ImageUrl
=
"~/Images/Landscape240.png"
/>
<
mob:AltImage
ImageUrl
=
"~/Images/Landscape480.png"
/>
<
mob:AltImage
ImageUrl
=
"~/Images/Landscape640.png"
/>
</
mob:Image
>
|
當初始化顯示圖像的時候,服務器將發送一個白色的1x1像素的GIF顯示在圖像所在位置。下面就是生成的HTML:
1
|
<
img
id
=
"B"
src
=
"P.axd?i=E.gif&i=1"
/>
|
一旦頁面裝載完成,JavaScript用來算出最終顯示圖像所須要的真正的尺寸,而後向服務器請求一個大小明確的圖像。通過JavaScript處理後,上面的HTML轉換爲:
1
|
<
img
id
=
"B"
src
=
"P.axd?i=1&w=500"
/>
|
web.config中引用的圖像處理器把i查詢字符串關聯到圖像源,所以服務器上最適合的圖像將用做調整的最初圖像。w查詢字符串參數指定了所請求圖像的寬度。所以不須要提供多個圖像;一個單獨的圖像幾乎就能夠了。 這種方法易於實現,並且結果是大小明確的圖像。這樣作不但減小了帶寬,並且還減小了移動電話CPU的運行週期和電量。
整個牛津大辭典包括171476個單詞。若是一個電腦用獨有的二進制數字表明一個單詞,而不是一個字母表的字母,大概須要用18比特(向上舍入大概3字節)。這代表壓縮算法是十分有效的。
然而,HTML不是頗有效,由於它充滿了用字符表明的元素、IDs,類,styles和Javascript,沒有考慮到是不是人可讀的。壓縮能夠減小這些,但仍是要有開銷的。這就是爲何流行的庫都有人們讀不懂的壓縮版本。
在服務器發送給瀏覽器以前,一些與標記相關的單詞還能夠最小化,並且不會丟失任何這些單詞的意義。看一個上面所示的圖像的例子,ASP.NET裏標準的HTML的圖像元素的ID屬性是ImageBanner。
1
|
<
mob:Image
runat
=
"server"
ID
=
"ImageBanner"
CalculateSizeMode
=
"ClientWidth"
Style
=
"clear: both; width: 100%"
>
|
然而發送給瀏覽器的代碼只使用B。對一個單獨的元素來講。這樣的性能改進是微不足道的,然而,對一個含有數百個元素的複雜頁面來講,傳送這樣的頁面會更快,並且瀏覽器將能更快地處理這一切。
圖像例子生成的HTML看起來比較奇怪:
1
|
<
img
id
=
"B"
src
=
"P.axd?i=1&w=500"
/>
|
這段ASP.NET代碼沒有樣式並且也沒有爲img元素設置CLASS屬性。那麼它的樣式是怎麼來的呢?
服務器端最小化過程當中將會肯定樣式信息,而且爲網頁建立一個CSS文件,從而減少了HTML的大小。當HTML變化時,樣式已經被緩存在瀏覽器中,不須要從新下載。CSS片斷看起來就像這樣:
1
|
#B{
clear
:
both
;
width
:
100%
;}
|
若是許多元素共享同一個樣式,那麼就要給這個CSS增長ID屬性,這樣它們就能夠共享相同的信息。
還能夠經過使用服務器端樣式元素實如今多個元素和頁面上共享樣式信息。下面的代碼擴展了前面圖像例子,以此來講明共享樣式元素。
1
2
3
4
5
|
<
mob:Style
runat
=
"server"
ID
=
"StyleBanner"
>
<
mob:Filter
Style
=
"clear: both; width: 100%"
/>
</
mob:Style
>
<
mob:Image
runat
=
"server"
ID
=
"ImageBanner"
CalculateSizeMode
=
"ClientWidth"
StyleID
=
"StyleBanner"
>
|
根據設備的能力,還能夠對這個元素進行進一步擴展,使得能夠應用其餘樣式,而且可在多個頁面上優化樣式表。 這種技術老是確保只傳輸必須的CSS,所以在對同一個頁面的後續請求方面提升了性能,尤爲是對HTML內容只有稍稍不一樣的頁面。
上面所示的圖像優化和動態最小化HTML和CSS內容的技術和代碼例子取決於頁面渲染以後且服務器傳送給瀏覽器以前更改的內容。這樣的預處理技術在諸如ASP.NET的Web表格這樣的結構裏實現起來至關容易。
然而在基於腳本的好比PHP這樣的架構裏實現它們就很是複雜。正是因爲這個緣由,而且爲了保持一致性,這篇文章中的例子都是在.NET上的。咱們已經可以把這種技術應用到其餘語言上,例子代碼可在朋友博客裏看到。
公共衛生基金會的企業實現了本文中提到的技術,並在第一週成功提升了23%的性能。
其餘比較注重性能的網站包括 24.com(媒體),ServiceTick(分析),LettingWeb(財產),AdSupply(廣告)和Kitsap Credit Union(金融)都使用了本文提到的部分或是所有的技術來優化他們的移動站點。
爲了真正地優化性能,咱們須要考慮網站全部人的投資回報。監測設備特徵的不一樣是根本起始點。
而後咱們才能部署諸如利用分散的移動網站來分離或改變內容焦點的解決方案。咱們還能經過收緊縮小圖像和HTML,移除jQuery,問詢什麼時候單獨使用響應式網站設計(RWD),以及其它技術等使性能達到最高。固然,現有的技術也是相當重要的,例如配置緩存路徑和壓縮內容。
微調咱們的開發環境,來模擬真實世界的狀況,這樣也能夠在整個開發過程當中得到對性能的更好的理解。
爲了能讓你更多地考慮性能,我已經設定好了一個尋找世界上最重型的網站的競賽。尋找一個網頁,它在移動電話上運行得很糟糕,並將其提交給競賽。咱們會比較頁面的份量,以及它是不是最重型的,你將所以而贏得1000美圓。與此同時,實現本文以及其餘Smashing Magazine中的牛文中提到的技術,以確保你的網站在被咱們掂量其性能的時候不會出如今榜單之首!
從未有過比這更能提升你的網站性能的機會了。