前端的高性能部分,主要是指減少請(qǐng)求數(shù)、減少傳輸?shù)臄?shù)據(jù)以及提高用戶體驗(yàn),在這個(gè)部分,圖片的優(yōu)化顯得至關(guān)重要。許多網(wǎng)站的美化,都是靠絢麗的圖片達(dá)到的,圖片恰恰是占用帶寬的元兇。每個(gè) img 標(biāo)簽,瀏覽器都會(huì)試圖發(fā)起一個(gè)下載請(qǐng)求。本文就詳細(xì)介紹了圖片優(yōu)化的幾種方式,介紹了使用的工具以及優(yōu)化后的結(jié)果。
減少圖片的大小,可以明顯的提高性能,而對(duì)于已有圖片,要想減少圖片的大小,只能改變圖片的格式,這里推薦的是 PNG8 的格式,它可以在基本保持清晰度的情況下,減少圖片的大小。知道這個(gè)原理以后,可以用 Windows 的畫圖工具、以及 PhotoShop 工具逐個(gè)的改變。但是這樣做的缺點(diǎn)是單張?zhí)幚?,效率太慢。本文推薦一個(gè)在線轉(zhuǎn)換工具 Smush.it,可以批量的進(jìn)行壓縮與轉(zhuǎn)換。它的地址是:www.smushit.com/ysmush.it。打開后效果如下圖所示。
圖 1. Yahoo 提供的在線壓縮工具

我們上傳了一張大小為 3790K 的圖片,待在線程序處理完畢后,點(diǎn)擊 Download Smushed Images 下載查看結(jié)果。下載界面如下圖所示。
圖 2. 壓縮后的結(jié)果

打開下載下來的壓縮包,查看結(jié)果可以看到,圖片從 3790 減少到了 3344,就如下圖所示。對(duì)于大批量的圖片網(wǎng)站,這個(gè)方法會(huì)幫助快速實(shí)現(xiàn)批量圖片壓縮。
圖 3. 壓縮后的結(jié)果

CSS Sprites 是一個(gè)吸引人的技術(shù),它其實(shí)就是把網(wǎng)頁中一些背景圖片整合到一張圖片文件中,再利用 CSS 的“background-image”,“background- repeat”,“background-position”的組合進(jìn)行背景定位,background-position 可以用數(shù)字能精確的定位出背景圖片的位置。利用 CSS Sprites 能很好地減少網(wǎng)頁的 HTTP 請(qǐng)求,從而大大的提高了頁面的性能,這也是 CSS Sprites 最大的優(yōu)點(diǎn),也是其被廣泛傳播和應(yīng)用的主要原因。CSS Sprites 能減少圖片的字節(jié),由于圖像合并后基本信息不用重復(fù),那么多張圖片合并成 1 張圖片的字節(jié)往往總是小于這些圖片的字節(jié)總和。同時(shí) CSS Sprites 解決了網(wǎng)頁設(shè)計(jì)師在圖片命名上的困擾,只需對(duì)一張集合的圖片上命名就可以了,不需要對(duì)每一個(gè)小元素進(jìn)行命名,從而提高了網(wǎng)頁的制作效率。更換風(fēng)格方便,只需要在一張或少張圖片上修改圖片的顏色或樣式,整個(gè)網(wǎng)頁的風(fēng)格就可以改變。維護(hù)起來更加方便。同時(shí),由于將圖片合并到一張圖片,因此圖片的請(qǐng)求數(shù)就被縮減到 1 個(gè)。其他的請(qǐng)求都可以用到本地緩存,不需要訪問服務(wù)器。下圖是一個(gè)合并以后的圖片。它將很多小圖標(biāo)都拼到了一起。
圖 4. 合并后的圖片

這里介紹一個(gè)小工具 ---“CSS Sprites 樣式生成工具 2.0”,可以從 這里下載。這是一個(gè)簡(jiǎn)單免費(fèi)的小工具,用該工具打開上面的圖片,選中圖片中的某塊。如下圖的“綠色大拇指”部分,工具會(huì)計(jì)算出這個(gè)部分的長、寬、距離左上角的距離。勾選復(fù)制類名、復(fù)制寬、復(fù)制高,再點(diǎn)擊“復(fù)制當(dāng)前樣式”按鈕。這樣生成的樣式會(huì)被復(fù)制到剪切板上。
圖 5. 小工具的使用

生成的 CSS 代碼如清單 1 所示。
清單 1. 小工具生成的 CSS 代碼
.div_6148{width:18px;height:20px;background-position:-17px -209px;} |
將這段代碼運(yùn)用在網(wǎng)頁上,它的代碼如下清單所示。
清單 2. 測(cè)試 CSS Sprites 代碼
<html> <head> <style> .div_6148 { width:18px; height:20px; background-image:url(css-sprites-source.gif); background-position:-17px -209px; } </style> </head> <body> <div class="div_6148"></div> </body> </html> |
打開測(cè)試網(wǎng)頁顯示結(jié)果如下圖所示。
圖 6. 測(cè)試網(wǎng)頁效果

可以看到,網(wǎng)頁只顯示工具選擇的“綠色大拇指”部分,這樣的代碼可以運(yùn)用在網(wǎng)頁的多個(gè)部分,而圖片只需要下載一次,這就是該技術(shù)的最大優(yōu)勢(shì),減少了因?yàn)樾D片引起的多個(gè)請(qǐng)求。
有時(shí)候,圖片數(shù)據(jù)太多,一些公司的解決方法是將圖片數(shù)據(jù)分到多個(gè)域名的服務(wù)器上,這在一方面是將服務(wù)器的請(qǐng)求壓力分到多個(gè)硬件服務(wù)器上。另一方面,是利用了瀏覽器的特性。一般來說,瀏覽器對(duì)于相同域名的圖片,最多用 2-4 個(gè)線程并行下載。不同瀏覽器的并發(fā)下載數(shù),都是不同的,并發(fā)數(shù)如下清單所示。
清單 3. 各瀏覽器的并發(fā)下載數(shù)
Browsers HTTP/1.1 HTTP/1.0 IE6,7 2 4 IE8 6 6 FireFox 2 2 8 FireFox 3 6 6 Safari 3,4 4 4 Chrome 1,2 6 ? Chrome 3 4 4 Opera 9.63,10.00alpha 4 4 |
而相同域名的其他圖片,則要等到其他圖片下載完后才會(huì)開始下載。 這里我做了一個(gè)測(cè)試,選擇了多個(gè)相同域名的圖片在同一網(wǎng)頁上。代碼如清單 5 所示。
清單 4. 單域名的多圖片下載
<html> <body> <img src="http://img1./news/pics/hv1/123/231/804/52339128.jpg"><br> <img src="http://img1./news/pics/hv1/87/235/804/52340112.jpg"><br> <img src="http://img1./finance/pics/hv1/41/119/804/52310486.jpg"><br> <img src="http://img1./sports/pics/hv1/246/198/804/52330836.jpg"><br> <img src="http://img1./ent/pics/hv1/101/54/805/52358996.jpg"><br> <img src="http://img1./blog/pics/hv1/169/226/804/52337899.jpg"> </body> </html> |
接下來,使用 FireFox 的 Firebug 插件監(jiān)控網(wǎng)絡(luò)。結(jié)果如下圖所示。
圖 7. 單域名多圖片的監(jiān)控效果

可以看到,相同域名的多張圖片,它們下載的起始點(diǎn)是存在延遲的。它們并不是并行下載。當(dāng)我們將其中的 3 張圖片換成別的域名圖片。如清單 6 所示。
清單 5. 多域名多圖片下載
<html> <body> <img src="http://img1./news/pics/hv1/123/231/804/52339128.jpg"><br> <img src="http://img1./news/pics/hv1/87/235/804/52340112.jpg"><br> <img src="http://img1./finance/pics/hv1/41/119/804/52310486.jpg"><br> <img src="http://i0./20110624/64a_2ee7d710_2ec6_b38d_b678_dc3af28392be_1.jpg"><br> <img src="http://i0./20110624/3b0_643eaea5_1233_b543_82b7_9c7273c7f97c_1.jpg"><br> <img src="http://i0./20110623/962_fa6e8a78_625a_1234_147f_3a627fe17033_1.jpg"> </body> </html> |
再次查看網(wǎng)絡(luò)監(jiān)控,可以看到,這些圖片是并行下載的。
圖 8. 多域名多圖片測(cè)試結(jié)果

多域名的下載固然很好,但是太多域名并不太好,一般在 2-3 個(gè)域名下載就差不多。
不管如何,圖片的下載始終都要向服務(wù)器發(fā)出請(qǐng)求,要是圖片的下載不用向服務(wù)器發(fā)出請(qǐng)求,而可以隨著 HTML 的下載同時(shí)下載到本地那就太好了。而目前,瀏覽器已經(jīng)支持了該特性,我們可以將圖片數(shù)據(jù)編碼成 BASE64 的字符串,使用該字符串代替圖像地址。假設(shè)用 S代表這個(gè) BASE64 字符串,那么就可以使用 <img src="data:image/png;base64,S"> 來顯示這個(gè)圖像。可以看出,圖像的數(shù)據(jù)包含在了 HTML 代碼里,無需再次訪問服務(wù)器。那么圖像要如何編碼成 BASE64 字符串呢?可以使用 在線的工具---“Base64 Online”,這個(gè)工具可以上傳圖片將圖片轉(zhuǎn)換為 BASE64 字符串。當(dāng)然,如果讀者有興趣,完全可以自己實(shí)現(xiàn)一個(gè) BASE64 編碼工具,比如使用 Java 開發(fā),它的代碼就如清單 7 所示。
清單 6. BASE64 的 Java 代碼
public static String getPicBASE64(String picPath) { String content = null; try { FileInputStream fis = new FileInputStream(picPath); byte[] bytes = new byte[fis.available()]; fis.read(bytes); content = new sun.misc.BASE64Encoder().encode(bytes); // 具體的編碼方法 fis.close(); } catch (Exception e) { e.printStackTrace(); } return content; } |
本文編碼了一個(gè)圖像,并且將編碼獲得的 BASE64 字符串,寫到了 HTML 之中,如下清單 8 所示。
清單 7. 嵌入 BASE64 的測(cè)試 HTML 代碼
<html> <body> <img src="data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAeQAAAB8BAMAAABKwt5QAAAAA3NCSVQICAjb4U/gAAAAGFBMVEX/ ……(省略了大部分編碼)… BJRU5ErkJggg=="> </body> </html> |
由于圖片數(shù)據(jù)包含在了 BASE64 字符串中,因此無需向服務(wù)器請(qǐng)求圖像數(shù)據(jù),結(jié)果顯示如下圖所示。
圖 9. BASE64 顯示圖像

然而這種策略并不能濫用,它適用的情況是瀏覽器連接服務(wù)器的時(shí)間 > 圖片下載時(shí)間,也就是發(fā)起連接的代價(jià)要大于圖片下載,那么這個(gè)時(shí)候?qū)D片編碼為 BASE64 字符串,就可以避免連接的建立,提高效率。如果圖片較大的話,使用 BASE64 編碼雖然可以避免連接建立,但是相對(duì)于圖像下載,請(qǐng)求的建立只占很小的比例,如果用 BASE64,對(duì)于動(dòng)態(tài)網(wǎng)頁來說圖像緩存就會(huì)失效(靜態(tài)網(wǎng)頁可以緩存),而且 BASE64 字符串的總大小要大于純圖片的大小,這樣一算就非常不合適了。因此,如果你的頁面已經(jīng)靜態(tài)化,圖像又不是非常大,可以嘗試 BASE64 編碼,客戶端會(huì)將網(wǎng)頁內(nèi)容和圖片的 BASE64 編碼一起緩存;而如果你的頁面是動(dòng)態(tài)頁面,圖像還較大,每次都要下載 BASE64 字符串,那么就不能用 BASE64 編碼圖像,而正常引用圖像,從而使用到瀏覽器的圖像緩存,提高下載速度。從現(xiàn)實(shí)我們接觸的角度看,如一些在線 HTML 編輯器,里面的小圖標(biāo),如笑臉等,都使用到了 BASE64 編碼,因?yàn)樗鼈兎浅P?,?shù)量多,BASE64 可以幫助網(wǎng)頁減少圖標(biāo)的請(qǐng)求數(shù),提高效率。
為了減少傳輸?shù)臄?shù)據(jù),壓縮是一個(gè)不錯(cuò)的選擇,而 HTTP 協(xié)議支持 GZIP 的壓縮格式,服務(wù)器響應(yīng)的報(bào)頭包含 Content-Encoding: gzip,它告訴瀏覽器,這個(gè)響應(yīng)的返回?cái)?shù)據(jù),已經(jīng)壓縮成 GZIP 格式,瀏覽器獲得數(shù)據(jù)后要進(jìn)行解壓縮操作。這在一定程度可以減少服務(wù)器傳輸?shù)臄?shù)據(jù),提高系統(tǒng)性能。那么如何給服務(wù)器響應(yīng)添加 Content-Encoding: gzip 報(bào)頭,同時(shí)壓縮響應(yīng)數(shù)據(jù)呢?如果你用的是 Tomcat 服務(wù)器,打開 $tomcat_home$/conf/server.xml 文件,對(duì) Connector 進(jìn)行配置,配置如清單 9 所示。
清單 8. TOMCAT 配置清單
<Connector port ="80" maxHttpHeaderSize ="8192" maxThreads ="150" minSpareThreads ="25" maxSpareThreads ="75" enableLookups ="false" redirectPort ="8443" acceptCount ="100" connectionTimeout ="20000" disableUploadTimeout ="true" URIEncoding ="utf-8" compression="on" compressionMinSize="2048" noCompressionUserAgents="gozilla, traviata" compressableMimeType="text/html,text/xml" /> |
我們?yōu)?Connector 添加了如下幾個(gè)屬性,他們意義分別是:
compression="on" 打開壓縮功能
compressionMinSize="2048" 啟用壓縮的輸出內(nèi)容大小,這里面默認(rèn)為 2KB
noCompressionUserAgents="gozilla, traviata" 對(duì)于以下的瀏覽器,不啟用壓縮
compressableMimeType="text/html,text/xml, image/png" 壓縮類型
有時(shí)候,我們無法配置 server.xml,比如如果我們只是租用了別人的空間,但是它并沒有啟用 GZIP,那么我們就要使用程序啟用 GZIP 功能。我們將需要壓縮的文件,放到指定的文件夾,使用一個(gè)過濾器,過濾對(duì)這個(gè)文件夾里文件的請(qǐng)求。
清單 9. 自定義 Filter 壓縮 GZIP
// 監(jiān)視對(duì) gzipCategory 文件夾的請(qǐng)求 @WebFilter(urlPatterns = { "/gzipCategory/*" }) public class GZIPFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { String parameter = request.getParameter("gzip"); // 判斷是否包含了 Accept-Encoding 請(qǐng)求頭部 HttpServletRequest s = (HttpServletRequest)request; String header = s.getHeader("Accept-Encoding"); //"1".equals(parameter) 只是為了控制,如果傳入 gzip=1,才執(zhí)行壓縮,目的是測(cè)試用 if ("1".equals(parameter) && header != null && header.toLowerCase().contains("gzip")) { HttpServletResponse resp = (HttpServletResponse) response; final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); HttpServletResponseWrapper hsrw = new HttpServletResponseWrapper( resp) { @Override public PrintWriter getWriter() throws IOException { return new PrintWriter(new OutputStreamWriter(buffer, getCharacterEncoding())); } @Override public ServletOutputStream getOutputStream() throws IOException { return new ServletOutputStream() { @Override public void write(int b) throws IOException { buffer.write(b); } }; } }; chain.doFilter(request, hsrw); byte[] gzipData = gzip(buffer.toByteArray()); resp.addHeader("Content-Encoding", "gzip"); resp.setContentLength(gzipData.length); ServletOutputStream output = response.getOutputStream(); output.write(gzipData); output.flush(); } else { chain.doFilter(request, response); } } // 用 GZIP 壓縮字節(jié)數(shù)組 private byte[] gzip(byte[] data) { ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(10240); GZIPOutputStream output = null; try { output = new GZIPOutputStream(byteOutput); output.write(data); } catch (IOException e) { } finally { try { output.close(); } catch (IOException e) { } } return byteOutput.toByteArray(); } …… } |
該程序的主體思想,是在響應(yīng)流寫回之前,對(duì)響應(yīng)的字節(jié)數(shù)據(jù)進(jìn)行 GZIP 壓縮,因?yàn)椴⒉皇撬械臑g覽器都支持 GZIP 解壓縮,如果瀏覽器支持 GZIP 解壓縮,會(huì)在請(qǐng)求報(bào)頭的 Accept-Encoding 里包含 gzip。這是告訴服務(wù)器瀏覽器支持 GZIP 解壓縮,因此如果用程序控制壓縮,為了保險(xiǎn)起見,還需要判斷瀏覽器是否發(fā)送 accept-encoding: gzip 報(bào)頭,如果包含了該報(bào)頭,才執(zhí)行壓縮。為了驗(yàn)證壓縮前后的情況,使用 Firebug 監(jiān)控請(qǐng)求和響應(yīng)報(bào)頭。
清單 10. 壓縮前請(qǐng)求
GET /testProject/gzipCategory/test.html HTTP/1.1 Accept: */* Accept-Language: zh-cn Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) Host: localhost:9090 Connection: Keep-Alive |
清單 11. 不壓縮的響應(yīng)
HTTP/1.1 200 OK Server: Apache-Coyote/1.1 ETag: W/"5060-1242444154000" Last-Modified: Sat, 16 May 2009 03:22:34 GMT Content-Type: text/html Content-Length: 5060 Date: Mon, 18 May 2009 12:29:49 GMT |
清單 12. 壓縮后的響應(yīng)
HTTP/1.1 200 OK Server: Apache-Coyote/1.1 ETag: W/"5060-1242444154000" Last-Modified: Sat, 16 May 2009 03:22:34 GMT Content-Encoding: gzip Content-Type: text/html Content-Length: 837 Date: Mon, 18 May 2009 12:27:33 GMT |
可以看到,壓縮后的數(shù)據(jù)比壓縮前數(shù)據(jù)小了很多。壓縮后的響應(yīng)報(bào)頭包含 Content-Encoding: gzip。同時(shí) Content-Length 包含了返回?cái)?shù)據(jù)的大小。GZIP 壓縮是一個(gè)重要的功能,前面提到的是對(duì)單一服務(wù)器的壓縮優(yōu)化,在高并發(fā)的情況,多個(gè) Tomcat 服務(wù)器之前,需要采用反向代理的技術(shù),提高并發(fā)度,而目前比較火的反向代理是 Nginx(這在后續(xù)的文章會(huì)進(jìn)行詳細(xì)的介紹)。對(duì) Nginx 的 HTTP 配置部分里增加如下配置。
清單 13. Nginx 的 GZIP 配置
gzip on; gzip_min_length 1000; gzip_buffers 4 8k; gzip_types text/plain application/x-javascript text/css text/html application/xml; |
由于 Nginx 具有更高的性能,利用該配置可以更好的提高性能。在高性能服務(wù)器上該配置將非常有用。
預(yù)加載和懶加載,是一種改善用戶體驗(yàn)的策略,它實(shí)際上并不能提高程序性能,但是卻可以明顯改善用戶體驗(yàn)或減輕服務(wù)器壓力。
預(yù)加載原理是在用戶查看一張圖片時(shí),就將下一張圖片先下載到本地,而當(dāng)用戶真正訪問下一張圖片時(shí),由于本地緩存的原因,無需從服務(wù)器端下載,從而達(dá)到提高用戶體驗(yàn)的目的。為了實(shí)現(xiàn)預(yù)加載,我們可以實(shí)現(xiàn)如下的一個(gè)函數(shù)。
清單 14. 預(yù)加載函數(shù)
function preload(callback) { var imageObj = new Image(); images = new Array(); images[0]="pre_image1.jpg"; images[1]=" pre_image2.jpg"; images[2]=" pre_image3.jpg"; for(var i=0; i<=2; i++) { imageObj.src=images[i]; if (imageObj.complete) { // 如果圖片已經(jīng)存在于瀏覽器緩存,直接調(diào)用回調(diào)函數(shù) callback.call(imageObj); } else { imageObj.onload = function () {// 圖片下載完畢時(shí)異步調(diào)用 callback 函數(shù) callback.call(imageObj);// 將回調(diào)函數(shù)的 this 替換為 Image 對(duì)象 }; } } } function callback() { alert(this.src + “已經(jīng)加載完畢 , 可以在這里繼續(xù)預(yù)加載下一組圖片”); } |
上面的代碼,首先定義了 Image 對(duì)象,并且聲明了需要預(yù)加載的圖像數(shù)組,然后逐一的開始加載(.src=images[i])。如果已經(jīng)在緩存里,則不做其他處理;如果不在緩存,監(jiān)聽 onload 事件,它會(huì)在圖片加載完畢時(shí)調(diào)用。
而懶加載則是在用戶需要的時(shí)候再加載。當(dāng)一個(gè)網(wǎng)頁中可能同時(shí)有上百張圖片,而大部分情況下,用戶只看其中的一部分,如果同時(shí)顯示上百張,則浪費(fèi)了大量帶寬資源,因此可以當(dāng)用戶往下拉動(dòng)滾動(dòng)條時(shí),才去請(qǐng)求下載被查看的圖像,這個(gè)原理與 word 的顯示策略非常類似。
在 JavaScript 中,它的基本原理是首先要有一個(gè)容器對(duì)象,容器里面是 img 元素集合。用隱藏或替換等方法,停止 img 的加載,也就是停止它去下載圖像。然后歷遍 img 元素,當(dāng)元素在加載范圍內(nèi),再進(jìn)行加載(也就是顯示或插入 img 標(biāo)簽)。加載范圍一般是容器的視框范圍,即瀏覽者的視覺范圍內(nèi)。當(dāng)容器滾動(dòng)或大小改變時(shí),再重新歷遍元素判斷。如此重復(fù),直到所有元素都加載后就完成。當(dāng)然對(duì)于開發(fā)來講,選擇已有的成熟組件,并不失為一個(gè)上策,Lazy Load Plugin for jQuery 是基于 JQuery 的懶加載組件,它有自己的 官方網(wǎng)站。這是一個(gè)不錯(cuò)的免費(fèi)插件??梢詭椭绦騿T快速的開發(fā)懶加載應(yīng)用。
本文總結(jié)了前端圖片高性能優(yōu)化的幾種方式,將它們歸結(jié)起來,在讀者需要的時(shí)候,可以查看本文的內(nèi)容,相信按照本文的方法,可以輔助讀者進(jìn)行前端的高性能優(yōu)化。筆者將繼續(xù)寫后續(xù)的部分,包括數(shù)據(jù)庫的優(yōu)化、負(fù)載均衡、反向代理等。包括由于筆者水平有限,如有錯(cuò)誤,請(qǐng)聯(lián)系我批評(píng)指正。
接下來在第二部分文章中,我將介紹前端的 BigPipe 技術(shù)、Flush 機(jī)制、動(dòng)靜分離、HTTP 持久連接、HTTP 協(xié)議靈活應(yīng)用、靜態(tài)化與偽靜態(tài)化、頁面緩存(整體、部分)等,并且將它們應(yīng)用到 Java Web 的開發(fā)中。使用這些技術(shù)可以幫助提高 Java Web 應(yīng)用程序的性能。
學(xué)習(xí)
- 參考“CSS Sprites 圖片切割術(shù)與圖片優(yōu)化”,具體了解 CSS Sprites 圖片切割術(shù)與圖片優(yōu)化的技術(shù)。
- 了解 “GZIP 壓縮詳解”,了解 GZIP 壓縮的詳細(xì)原理。
- 查看“深入理解 HTTP 協(xié)議”,了解 HTTP 協(xié)議,更加理解 HTTP 的含義。
- 查看“CSS Sprite”,了解 CSS Sprite 的發(fā)源和原理。
- 查看“當(dāng)前瀏覽器的并行下載數(shù)”,查看瀏覽器的并行下載數(shù)。
- 查看“淺談 BASE64”,了解 BASE64 的基本原理。
- 查看“預(yù)加載與懶加載”,大致了解預(yù)加載與懶加載的原理和概念。
- developerWorks Web development 專區(qū):通過專門關(guān)于 Web 技術(shù)的文章和教程,擴(kuò)展您在網(wǎng)站開發(fā)方面的技能。
- developerWorks Ajax 資源中心:這是有關(guān) Ajax 編程模型信息的一站式中心,包括很多文檔、教程、論壇、blog、wiki 和新聞。任何 Ajax 的新信息都能在這里找到。
- developerWorks Web 2.0 資源中心,這是有關(guān) Web 2.0 相關(guān)信息的一站式中心,包括大量 Web 2.0 技術(shù)文章、教程、下載和相關(guān)技術(shù)資源。您還可以通過 Web 2.0 新手入門 欄目,迅速了解 Web 2.0 的相關(guān)概念。
- 查看 HTML5 專題,了解更多和 HTML5 相關(guān)的知識(shí)和動(dòng)向。
討論
- 加入 developerWorks 中文社區(qū)。查看開發(fā)人員推動(dòng)的博客、論壇、組和維基,并與其他 developerWorks 用戶交流。
為本文評(píng)分
平均分 (74個(gè)評(píng)分)