託管 AJAX 能否讓 Web 應用程式提速?

天府雲創發表於2017-11-20

有關本主題的多項研究表明,建立 AJAX Web 應用程式時遇到的兩個最重要問題是,執行速度和響應速度。這可能是一些開發者選擇建立原生應用程式(而不是 Web 應用程式)的部分原因所在。

但如果我說有一種方法可以建立執行速度和響應速度比現有應用程式快 100 倍的 AJAX Web 應用程式,又如何呢?

我發明了一種方法,用於建立基於 Java 的純正 AJAX Web 應用程式,至少可以將應用程式的頻寬使用降低 10 倍,有時降幅可達 300 倍之多,具體視要使用的工具型別及要建立的內容而定。我將此技術稱為“託管 AJAX”。

在某種程度上,我是受到 Microsoft 生成公共語言執行時 (CLR) 的方式啟發,發明了託管 AJAX。例如,在使用者建立 C# 應用程式時,編譯器會建立 CLR 程式集。這意味著,最終結果的執行時環境是“託管環境”。

建立託管 AJAX 應用程式時,最終的編譯結果只會是普通的 ASP.NET 網站;它會變成託管環境,其中最終結果的 Java 部分會被完全抽取出來,操作方式與擁有 CLR 程式集時將 CPU 指令抽取出來一樣。

這是如何實現的呢?

幾乎不需要掌握任何新知識,即可使用託管 AJAX。如果已完成任一 ASP.NET 開發,可以將新的控制元件庫拖到 .aspx 頁面,再繼續完成工作,操作方式幾乎與之前完全相同。

在 .aspx 標記或 C#/F#/Visual Basic .NET 程式碼隱藏頁面中建立幾個 ASP.NE 控制元件。然後,修飾這些控制元件的屬性,並新增幾個 AJAX 事件處理程式,這樣就大功告成了!

初始呈現生成的是普通舊 HTML。不過,在 AJAX 請求期間在伺服器端對任意控制元件做出的所有更改,都會以 JSON 的形式傳遞到客戶端。

因此,客戶端可以獲得總大小不到 5KB 的微型 Java 庫,使用者可以建立各種 AJAX 控制元件(如 TreeView、DataGrid 和 TabView),從來都不需要使用超過 5KB 的 Java。

此時便會發現,已超出用作獨立 Java 檔案的 jQuery 幾乎一個數量級(縮小和 Zopfli 壓縮後的 jQuery 版本 2.1.3 為 30KB)。因此,只在頁面上新增 jQuery,而不新增其他任何 Java,頻寬使用已是使用託管 AJAX 方法時的 6 倍。開始在自己的 Java 中使用 jQuery 時,此數值就會猛增。

拉取縮小和壓縮版本的 jQuery UI 會導致 Java 部分增加 73.5KB。只在頁面上新增 jQuery 和 jQuery UI,大小會再增加 103.4KB(用 103.4KB 除以 4.8KB,可以得出頻寬消耗增大了 21.5 倍)。

此時,仍尚未在頁面上建立任何 UI 元素,但 jQuery 和 jQuery UI 佔用的空間就幾乎是託管 AJAX 方法的 22 倍。使用這 5KB 的 Java,可以建立幾乎所有夢寐以求的 UI 小元件,包括 jQuery 和 jQuery UI 可以建立的大部分 UI 控制元件。

無論執行哪種操作,基本上很少會(如果有過)超過這 5KB 的 Java 限制。應用程式的其他部分(如 HTML 和 CSS)也可能會變小很多。

使用這種方法,可以建立各種 AJAX UI 控制元件,如 AJAX TreeView 控制元件、DataGrid 控制元件和 TabView 控制元件。而且,建立這些小元件時,永遠都不需要額外新增 Java。此外,無需掌握任何新知識,即可使用這些控制元件。它們的使用方法(幾乎)與在 ASP.NET 中使用傳統 WebControl 的方法相同。

託管 AJAX 方法提供兩種不同的方式,用於處理頁面收到的 HTTP 請求。一種處理程式是普通 HTTP 請求,可直接向客戶端提供 HTML。另一種處理程式支援檢查是否有 HTTP POST 引數。

若有此引數,處理程式只會以 JSON 形式將各個控制元件的更改重新呈現給客戶端。在 AJAX 請求期間,將會自動重新建立通過修改頁面的控制元件層次結構而建立的所有控制元件,其中包含舊請求內的屬性。

客戶端上有一個常規處理程式,可處理控制元件的 JSON 屬性,一般會更新客戶端上 DOM 元素的屬性和 DOM 事件處理程式。

這種方法帶來了許多積極影響,如可以直接按原樣呈現 HTML 元素,這樣就不會干擾 Web 的最初建立方式了。這意味著,Web 應用程式在語義上變得更易於理解(例如,被搜尋引擎蜘蛛程式理解)。此外,若要做到盡善盡美,它還可以建立一個優質環境,用於實際修改客戶端上的內容。

仍可以根據需要將這種方法與任意數量的自定義 Java 結合使用。在這種情況下,只需檢查普通 HTML 請求中呈現的 HTML 即可。比較這種方法與其他許多 AJAX UI 庫(通常包含許多兆位元組的 Java,用於建立 DataGrid 和 TreeView)使用的“神奇 div”方法。

這樣,就可以理解執行速度和響應速度快 100 倍並不是誇大其詞。實際上,相較於與 C# 和 ASP.NET 結合使用的所有最常用元件 UI 工具包,在頻寬消耗方面,它的執行速度和響應速度通常可快 100 倍到 250 倍。

我最近測量了 System42 中的託管 AJAX TreeView 小元件與 ASP.NET 堆疊上的三個最大元件工具包的效能值。我發現,在頻寬消耗方面,執行速度和響應速度的差異介於 150 倍到 220 倍之間。

為了能夠理解這其中的真正含義,假設 Internet 連線速度極慢,需要一秒才能下載 5KB 的 Java。這意味著,一秒就可以下載託管 AJAX Java;若要下載其他一些工具包的 Java 部分,可能需要長達 3 分 40 秒之久。如果使用這兩種方法生成兩個電子商務解決方案,在轉換方面,無需多言,就可以想象差異是多麼巨大。

程式碼展示

好了,閒話少說,接下來將做些實際工作。首先,從 bit.ly/2u5W0EO下載 Phosphorus Five。接下來,開啟 p5.sln 檔案,並生成 Phosphorus Five,以便可以轉到 p5.ajax.dll 程式集。

由於將在 Web 應用程式中將 p5.ajax.dll 用作引用,因此需要先生成它,然後才能繼續操作。請注意,Phosphorus Five 包含超過 30 專案,但在本文中我將重點介紹 p5.ajax 專案。

接下來,在 Visual Studio 中新建一個 ASP.NET 網站。請務必建立 Web 窗體應用程式。在 Visual Studio for Mac 中,可以在“檔案 | 新建解決方案 | 其他 | .NET | ASP.NET Web 窗體專案”下找到此應用程式。

在新建的網站中,建立對已生成的 p5.ajax.dll 程式集的引用,並按照如下程式碼修改 web.config:

<?xml version="1.0"?><configuration> <system.web> <pages clientIDMode="Static"> <controls> <add assembly="p5.ajax"namespace="p5.ajax.widgets"tagPrefix="p5"/> </controls> </pages> <compilation debug="true"targetFramework="4.5"/> <httpRuntime targetFramework="4.5"/> </system.web></configuration>

此程式碼中最重要的部分是“clientIDMode”和“add assembly”。 此時,可以在 .aspx 標記中使用任意 p5.ajax 控制元件,只需在它們前面新增字首 p5 即可。請務必按照圖 1 中的程式碼,修改 Default.aspx 頁面的內容。

圖 1:建立頁面,其中包含一個在獲得單擊後更改文字的按鈕

<%@ Page Language="C#"Inherits="foobar.Default"%><!DOCTYPE html><html><head runat="server"> <title>Default</title></head><body> <form id="form1"runat="server"> <p5:Literal runat="server"id="foo"onclick="foo_onclick"Element="button">Click me!</p5:Literal> </form></body></html>

然後,將它的程式碼隱藏頁面更改為如下所示:

usingSystem;namespacefoobar{ publicpartialclassDefault : p5.ajax.core.AjaxPage { [p5.ajax.core.WebMethod] publicvoidfoo_onclick(p5.ajax.widgets.Literal sender, EventArgs args) { sender.innerValue = "Hello World from Managed Ajax!"; } }}

請注意,必須先從 AjaxPage 繼承頁面,將 WebMethod 屬性新增到事件處理程式,再將事件處理程式的第一個引數專門強型別化為“Literal”小元件。現在,可以啟動網站,單擊按鈕並檢視結果。

如果在除錯網站時看到不可思議的 bug,請務必禁用 Visual Studio 的“瀏覽器連結”設定(通常需要單擊 Visual Studio 頂部的一個工具欄按鈕)。如果對此時出現的情況感到很好奇,請嘗試檢查 HTTP 請求。此外,還請務必檢查它的初始 HTML。

呦,那是怎麼回事?

這就是託管 AJAX 的實際效果對於此概念,應注意以下幾個要點。首先,可以通過頁面中的任意 AJAX 事件處理程式,修改頁面上任何控制元件的所有屬性。如果建立了另一 Literal 小元件(例如,“Element”型別“p”),可以通過按鈕的“foo_onclick”事件處理程式,更新它的內容。

其次,可以任何認為適當的方式,在小元件中動態新增、刪除、更新或檢索任意屬性。若要引用任意屬性或事件處理程式,只需使用 C# 中的下標運算子即可。在圖 2 中,沒有設定小元件的 innerValue,而是使用 CSS 樣式屬性,檢查它的 style 屬性,並切換黃色背景。

請注意,它可以暫留並“記住”小元件的 style 屬性。另請注意,這樣做並沒有在客戶端與伺服器之間來回傳遞大量 ViewState。

在實際應用程式中,建議使用 CSS 類。為此,可以將圖 2 中的引用從“style”轉換為“class”。 不過,我希望保持此示例的簡單性,因此並沒有混用 CSS 檔案,而是為方便起見使用了 style 屬性。使用圖 2 中的方法,可以根據需要在頁面的所有小元件上新增、刪除和更改任何屬性。

圖 2:切換背景色

usingSystem;namespacefoobar{ publicpartialclassDefault : p5.ajax.core.AjaxPage { [p5.ajax.core.WebMethod] publicvoidfoo_onclick(p5.ajax.widgets.Literal sender, EventArgs args) { if(sender.HasAttribute ("style")) sender.DeleteAttribute ("style"); elsesender ["style"] = "background-color:Yellow;"; } }}

第三(可能也是最重要的一點),可以認為適當的方式,在其他任何小元件中動態新增、刪除、更新和插入任意新 AJAX 控制元件。不過,在介紹這最後一個要點之前,大家需要先檢查是否有“三個一組的小元件”。

p5.ajax 中有三個不同的小元件,但它們的 API 非常相似。通過合成將這三個小元件組合在一起後,可以建立任何所需的 HTML 標記。圖 2 中的示例使用了 Literal 小元件。Literal 小元件的“innerValue”屬性在客戶端上對映到“innerHTML”,只允許以字串或 HTML 的形式更改它的內容。

Container 小元件可以包含小元件。它會記住自己的控制元件集合,並允許在 AJAX 請求期間動態新增、刪除或更改它的控制元件集合。

第三個小元件是 Void 小元件,專用於不包含任何內容的控制元件,如 HTML 輸入元素、br 元素、hr 元素等。對於此處的示例而言,最重要的一個大概就是 Container 小元件。請繼續將 .aspx 頁面中的程式碼更改為圖 3 中所示。

圖 3:建立包含按鈕和專案符號列表(有一個列表項)的頁面

<%@ Page Language="C#"Inherits="foobar.Default"%><!DOCTYPE html><html><head runat="server"> <title>Default</title></head><body> <form id="form1"runat="server"> <p5:Literal runat="server"id="foo"onclick="foo_onclick"Element="button">Click me!</p5:Literal> <p5:Container runat="server"id="bar"Element="ul"> <p5:Literal runat="server"id="initial"onclick="initial_onclick"Element="li">Initial list element, tryclicking me!</p5:Literal> </p5:Container> </form></body></html>

圖 3 中的小元件層次結構將建立一個“button”和一個“ul”元素(其中包含一個“li”子元素)。接下來,按照圖 4 中的程式碼,更改 C# 程式碼隱藏頁面。

圖 4:對映 AJAX 事件處理程式以新建列表項

usingSystem;namespacefoobar{ publicpartialclassDefault : p5.ajax.core.AjaxPage { protectedp5.ajax.widgets.Container bar; [p5.ajax.core.WebMethod] publicvoidfoo_onclick(p5.ajax.widgets.Literal sender, EventArgs args) { // Using the factory method to create a new child widget for our "ul" widget.varwidget = bar.CreatePersistentControl<p5.ajax.widgets.Literal>(); widget.Element = "li"; widget.innerValue = "Try clicking me too!"; // Notice we supply the name of the method below here.widget ["onclick"] = "secondary_onclick"; } [p5.ajax.core.WebMethod] publicvoidinitial_onclick(p5.ajax.widgets.Literal sender, EventArgs args) { sender.innerValue = "I was clicked!"; } [p5.ajax.core.WebMethod] publicvoidsecondary_onclick(p5.ajax.widgets.Literal sender, EventArgs args) { sender.innerValue = "I was ALSO clicked!"; } }}

請注意,最後一行程式碼將新的小元件動態插入了 Container 小元件。新的“li”元素基本上已在 AJAX 請求期間被動態追加到了“ul”元素中,這樣做就成了!同時,還跨 AJAX 請求永久性地記住了這些小元件,因此可以更改它們的屬性,並呼叫它們的事件處理程式。

此外,通過“Element”屬性,還可以呈現任何 HTML 元素,並能藉助下標運算子新增任何屬性。

現在可以完全控制 HTML 標記,並能建立微型 AJAX 請求和響應,從而以認為適當的方式更新要在頁面上更新的任何內容。只使用 4.8KB 的 Java,就實現了這一切。已將 Web 應用程式 AJAX 開發變成與普通舊 Windows 窗體開發一樣易於實現。在此過程中,Web 應用程式的執行速度和響應速度最終快了 100 倍。

練習使用 Hyperlambda

數月前,我在 2017 年 6 月刊《MSDN 雜誌》中撰寫了“使用 Hyperlambda 讓 C# 更加動態化”(msdn.com/magazine/mt809119) 一文,探討了植根於執行樹的非傳統 Hyperlambda 程式語言。

之所以提到它是因為,藉助 Hyperlambda 基於樹的方法,宣告 AJAX 小元件層次結構變得極其簡單。將 p5.ajax 和 Hyperlambda 相結合,從而使用 AJAX TreeView 小元件,一些顯著的效果立刻顯現。

我們來研究一下。首先,除了 Phosphorus Five 之外,還需要按照 bit.ly/2vbkNpg中的說明操作,將 System42 下載到主 p5.webapp 資料夾中。然後,啟動 System42(其中包含超快的 AJAX TreeView 小元件),開啟“CMS”,單擊“+”新建 lambda 頁面,並貼上圖 5 中的程式碼。

圖 5:建立支援遍歷磁碟上資料夾的 AJAX TreeView

create-widget parent:content widgets sys42.widgets.tree crawl:trueitems root:/ .on-get-items list-folders:x:/../*/_item-id?value for-each:x:/@list-folders/*?name list-folders:x:/@_dp?value split:x:/@_dp?value =:/ add:x:/../*/return/* src:@"{0}:{1}" :x:/@split/0/-?name :x:/@_dp?value if:x:/@list-folders/* not add:x:/../*/return/*/items/0/- src class:tree-leaf returnitems

單擊“設定”,選擇“空”作為“模板”,單擊“確定”,儲存頁面並單擊“檢視頁面”。

在檢查 HTTP 請求通過網路傳輸的內容時,嘗試展開 AJAX TreeView,便會意識到剛剛生成了一個可瀏覽資料夾的 AJAX TreeView,只使用了 24 行 Hyperlambda 來顯示 p5.webapp 資料夾中的資料夾,而初始總頻寬消耗僅為 10.9KB!

如果將這些結果與其他任何 AJAX 工具包進行比較,通常都會發現,除了通過網路傳輸的其他所有內容之外,其他工具包還需要下載許多兆位元組的 Java,而 Hyperlambda TreeView 包含的 Java 則不超過 4.8KB。

生成此 AJAX TreeView,總共使用了 717 行純 Hyperlambda 程式碼,並且僅使用了 Literal、Container 和 Void 小元件。大部分程式碼都包含註釋,因此建立 AJAX TreeView 控制元件需要約 300 行程式碼。

使用小元件需要 24 行 Hyperlambda,以便可以瀏覽磁碟上的資料夾。不過,使用其他任何工具建立此控制元件將需要數千行程式碼,使用它也需要數百行程式碼,這在圖 5 中只需要 24 行程式碼即可完成。

如果需要,現在可以轉換 Hyperlambda 示例中的三行程式碼,最終生成自己專用的活動事件自定義小元件,這樣通過一行程式碼就可以使用專用小元件了。有關具體操作說明,請訪問 bit.ly/2t96gsQ

因此,現在可以建立 AJAX TreeView,僅通過一行程式碼就能瀏覽伺服器的資料夾。若要在其他工具包中建立等效項,通常需要涉及四種不同語言的數百行程式碼。而我們只通過涉及一種程式語言的一行程式碼,便實現了這一切,並且與競爭對手相比,效能速度最多可快 300 倍。

總結

想象一下,結果無論是在質量、速度、優化性、bug 數量方面,還是在效率方面,都比之前提升了 100 倍。若要確保使用的是最新產品,請從 bit.ly/2uwNv65下載 Phosphorus Five,並從 bit.ly/2vbkNpg下載 System42。

相關文章