1C:Enterprise 技術的優點之一是,使用託管表單技術開發的應用程序解決方案既可以在 Windows、Linux、MacOS X 下的瘦(可執行)客戶端中啟動,也可以作為 5 種瀏覽器的 Web 客戶端啟動 - Chrome、Internet Explorer、Firefox、Safari、Edge 等都無需更改應用程序的源代碼。 此外,從外部來看,瘦客戶端中的應用程序和瀏覽器中的應用程序的功能和外觀幾乎相同。
找出10個不同點(下切2張圖):
Linux 上的瘦客戶端窗口:
Web 客戶端中的同一窗口(在 Chrome 瀏覽器中):
我們為什麼要做網絡客戶端? 說來有點可悲的是,時間給了我們這樣的任務。 長期以來,通過互聯網進行工作已經成為業務應用的先決條件。 首先,我們為瘦客戶端添加了通過互聯網工作的能力(順便說一句,我們的一些競爭對手就此止步;相反,其他競爭對手則放棄了瘦客戶端,只限於實現 Web 客戶端)。 我們決定讓用戶有機會選擇最適合他們的客戶端選項。
向瘦客戶端添加 Web 功能是一項艱鉅的任務,需要徹底改變客戶端/服務器架構。 創建 Web 客戶端是一個從頭開始的全新項目。
制定問題
所以,項目的要求:Web客戶端必須做和瘦客戶端一樣的事情,即:
- 顯示用戶界面
- 執行1C語言編寫的客戶端代碼
1C 中的用戶界面是在可視化編輯器中描述的,但是是聲明性的,沒有元素的逐像素排列; 使用了大約三打類型的界面元素 - 按鈕、輸入字段(文本、數字、日期/時間)、列表、表格、圖表等。
1C 語言的客戶端代碼可以包含服務器調用、使用本地資源(文件等)、打印等等。
瘦客戶端(通過 Web 工作時)和 Web 客戶端都使用同一組 Web 服務與 1C 應用程序服務器進行通信。 當然,客戶端的實現是不同的 - 瘦客戶端是用 C++ 編寫的,Web 客戶端是用 JavaScript 編寫的。
歷史上的位
Web 客戶端項目始於 2006 年,團隊(平均)有 5 人。 在項目的某些階段,開發人員參與實現特定功能(電子表格文檔、圖表等); 通常,這些開發人員在瘦客戶端中實現了此功能。 那些。 開發人員用 JavaScript 重寫了他們之前用 C++ 創建的組件。
從一開始,我們就拒絕將瘦客戶端 C++ 代碼自動(至少部分)轉換為 Web 客戶端 JavaScript,因為這兩種語言之間存在強烈的概念差異; Web 客戶端是用 JavaScript 從頭開始編寫的。
在項目的第一次迭代中,Web 客戶端將內置 1C 語言的客戶端代碼直接轉換為 JavaScript。 瘦客戶端的行為有所不同——內置1C語言中的代碼被編譯成字節碼,然後這個字節碼在客戶端上被解釋。 隨後,Web 客戶端開始做同樣的事情 - 首先,它提供了性能增益,其次,它使得統一瘦客戶端和 Web 客戶端的架構成為可能。
具有 Web 客戶端支持的 1C:Enterprise 平台的第一個版本於 2009 年發布。 當時的 Web 客戶端支持 2 種瀏覽器 - Internet Explorer 和 Firefox。 最初的計劃是支持 Opera,但由於當時 Opera 中的應用程序關閉處理程序存在無法克服的問題(無法 100% 確定地跟踪應用程序正在關閉,並且此時要執行從這些計劃中的 1C 應用程序服務器)不得不被放棄。
項目結構
1C:Enterprise 平台總共有 4 個用 JavaScript 編寫的項目:
- WebTools - 其他項目使用的共享庫(這裡包括
谷歌關閉庫 ). - 控制元素
格式化文檔 (在瘦客戶端和 Web 客戶端中均以 JavaScript 實現) - 控制元素
調度器 (在瘦客戶端和 Web 客戶端中均以 JavaScript 實現) - 網頁客戶端
每個項目的結構類似於 Java 項目(或 .NET 項目 - 以更接近您的為準)的結構; 我們有命名空間,每個命名空間都位於一個單獨的文件夾中。 文件夾內包含文件和命名空間類。 Web客戶端項目中有大約1000個文件。
從結構上來說,Web客戶端主要分為以下子系統:
- 託管客戶端應用程序接口
- 通用應用程序界面(系統菜單、面板)
- 託管表單界面,其中包括約 30 個控件(按鈕、各種類型的輸入字段 - 文本、數字、日期/時間等、表格、列表、圖表等)
- 客戶端可供開發者使用的對像模型(總共400多種:託管接口對像模型、數據組合設置、條件格式化等)
- 嵌入式語言解釋器1C
- 瀏覽器擴展(用於 JavaScript 不支持的功能)
- 使用密碼學
- 處理文件
- 外部組件技術允許它們在瘦客戶端和 Web 客戶端中使用
發展特點
在 JavaScript 中實現上述所有內容並不是一件容易的事。 也許 1C Web 客戶端是用 JavaScript 編寫的最大的客戶端應用程序之一 - 大約 450.000 行。 我們在 Web 客戶端代碼中積極使用面向對象的方法,這簡化瞭如此大的項目的工作。
為了最小化客戶端代碼的大小,我們首先使用了我們自己的混淆器,從平台版本8.3.6(2014年XNUMX月)開始我們開始使用
- 自己的混淆器 - 1556 kb
- Google 閉包編譯器 - 1073 kb
與我們自己的混淆器相比,使用 Google Closure 編譯器幫助我們將 Web 客戶端的性能提高了 30%。 此外,應用程序消耗的內存量減少了 15-25%(取決於瀏覽器)。
Google Closure Compiler 可以很好地處理面向對象的代碼,因此它的效率對於 Web 客戶端來說是最高的。 閉包編譯器為我們做了一些好事:
- 項目構建階段的靜態類型檢查(通過我們使用 JSDoc 註釋覆蓋代碼來提供)。 結果是靜態類型,與 C++ 中的類型非常接近。 這有助於在項目的編譯階段捕獲相當大比例的錯誤。
- 通過混淆減少代碼大小
- 對可執行代碼進行多項優化,例如:
- 內聯函數替換。 在 JavaScript 中調用函數是一項相當昂貴的操作,頻繁使用的小方法的內聯替換可以顯著加快代碼速度。
- 在編譯時計算常量。 如果表達式依賴於常量,它將被替換為常量的實際值
我們使用 WebStorm 作為我們的 Web 客戶端開發環境。
對於代碼分析,我們使用
我們完成/正在解決哪些任務
在項目實施過程中,我們面臨著許多必須解決的有趣任務。
與服務器以及窗口之間的數據交換
在某些情況下,源代碼的混淆可能會干擾系統的運行。 由於混淆,Web 客戶端可執行代碼外部的代碼可能具有與我們的可執行代碼期望的函數和參數名稱不同的函數和參數名稱。 我們的外部代碼是:
- 來自服務器的代碼作為數據結構
- 另一個應用程序窗口的代碼
為了避免與服務器交互時出現混淆,我們使用@expose標籤:
/**
* @constructor
* @extends {Base.SrvObject}
*/
Srv.Core.GenericException = function ()
{
/**
* @type {string}
* @expose
*/
this.descr;
/**
* @type {Srv.Core.GenericException}
* @expose
*/
this.inner;
/**
* @type {string}
* @expose
*/
this.clsid;
/**
* @type {boolean}
* @expose
*/
this.encoded;
}
為了避免與其他窗口交互時出現混淆,我們使用所謂的導出接口(所有方法均可導出的接口)。
/**
* Экспортируемый интерфейс контрола DropDownWindow
*
* @interface
* @struct
*/
WebUI.IDropDownWindowExp = function(){}
/**
* Перемещает выделение на 1 вперед или назад
*
* @param {boolean} isForward
* @param {boolean} checkOnly
* @return {boolean}
* @expose
*/
WebUI.IDropDownWindowExp.prototype.moveMarker = function (isForward, checkOnly){}
/**
* Перемещает выделение в начало или конец
*
* @param {boolean} isFirst
* @param {boolean} checkOnly
* @return {boolean}
* @expose
*/
WebUI.IDropDownWindowExp.prototype.moveMarkerTo = function (isFirst, checkOnly){}
/**
* @return {boolean}
* @expose
*/
WebUI.IDropDownWindowExp.prototype.selectValue = function (){}
我們在虛擬 DOM 成為主流之前就使用了它)
與所有處理複雜 Web UI 的開發人員一樣,我們很快意識到 DOM 不太適合動態用戶界面。 幾乎立即,虛擬 DOM 的類似物就被實現來優化 UI 的工作。 在事件處理期間,所有 DOM 更改都存儲在內存中,並且只有當所有操作完成時,累積的更改才會應用到 DOM 樹。
網頁客戶端優化
為了讓我們的網絡客戶端運行得更快,我們嘗試最大限度地使用瀏覽器的標準功能(CSS等)。 因此,表單命令欄(幾乎位於每個應用程序表單上)完全由瀏覽器繪製,基於 CSS 的動態佈局。
測試
對於功能和性能測試,我們使用我們自己的工具(用Java和C++編寫),以及基於以下內容構建的一組測試
我們的工具是通用的 - 它允許您測試幾乎所有窗口程序,因此適合測試瘦客戶端和 Web 客戶端。 該工具將啟動 1C 應用程序解決方案的用戶的操作記錄到腳本文件中。 同時,記錄屏幕工作區域(標準)的圖像。 當監控新版本的 Web 客戶端時,會在沒有用戶參與的情況下播放場景。 如果屏幕截圖在任何步驟與參考屏幕不匹配,則測試被視為失敗,之後質量專家將進行調查 - 這是一個錯誤還是系統行為的計劃更改。 在計劃行為的情況下,標準會自動被新標準取代。
該工具還以 25 毫秒的精度測量應用程序性能。 在某些情況下,我們會循環部分腳本(例如,多次重複訂單輸入)來分析執行時間隨時間的下降情況。 所有測量的結果都記錄在日誌中以供分析。
我們的測試工具和被測應用程序
我們的工具和 Selenium 相輔相成; 例如,如果其中一個屏幕上的某個按鈕更改了其位置 - Selenium 可能不會跟踪它,但我們的工具會注意到,因為將屏幕截圖與標准進行逐像素比較。 此外,該工具還能夠跟踪處理鍵盤或鼠標輸入的問題,因為它會重現這些輸入。
對這兩種工具(我們的工具和 Selenium)的測試都運行我們應用程序解決方案中的典型工作場景。 1C:Enterprise 平台每日構建後會自動啟動測試。 如果腳本速度變慢(與之前的版本相比),我們將調查並修復速度變慢的原因。 我們的標準很簡單 - 新組件的工作速度不應比前一個組件慢。
開發人員使用不同的工具來調查減速事件; 主要使用
此外,性能下降的原因之一可能是 Google Closure 編譯器由於某種原因無法對函數進行內聯替換(例如,因為函數是遞歸函數或虛擬函數)。 針對這種情況,我們嘗試通過重寫源代碼來補救。
瀏覽器擴展
如果應用的解決方案需要 JavaScript 之外的功能,我們會使用瀏覽器擴展:
- 處理文件
- 使用密碼學
- 與...一起工作
外部元件
我們的擴展由兩部分組成。 第一部分是所謂的瀏覽器擴展(通常是 Chrome 和 Firefox 的 JavaScript 擴展),它與第二部分交互,這是一個實現我們需要的功能的二進制擴展。 應該提到的是,我們編寫了 3 個版本的二進制擴展 - 適用於 Windows、Linux 和 MacOS。 二進制擴展作為 1C:Enterprise 平台的一部分提供,位於 1C 應用程序服務器上。 第一次從 Web 客戶端調用它時,它會下載到客戶端計算機並安裝在瀏覽器中。
當在 Safari 中運行時,我們的擴展使用 NPAPI;當在 Internet Explorer 中運行時,我們的擴展使用 ActiveX 技術。
進一步的發展
Web 客戶端開發團隊的任務組之一是進一步開發功能。 Web 客戶端的功能應與瘦客戶端的功能相同,所有新功能均在瘦客戶端和 Web 客戶端中同時實現。
其他任務包括架構開發、重構、性能和可靠性改進。 例如,方向之一是進一步轉向異步工作模型。 目前,Web 客戶端的部分功能是建立在與服務器交互的同步模型之上的。 異步模型現在在瀏覽器中變得越來越重要(而不僅僅是在瀏覽器中),這迫使我們通過用異步調用替換同步調用來修改 Web 客戶端(並相應地重構代碼)。 逐漸過渡到異步模型的原因是需要支持已發布的解決方案並逐漸適應它們。
來源: www.habr.com