<menu id="ycqsw"></menu><nav id="ycqsw"><code id="ycqsw"></code></nav>
<dd id="ycqsw"><menu id="ycqsw"></menu></dd>
  • <nav id="ycqsw"></nav>
    <menu id="ycqsw"><strong id="ycqsw"></strong></menu>
    <xmp id="ycqsw"><nav id="ycqsw"></nav>
  • websocket缺點有哪些(詳解websocket應用及優缺點)


    背景

    做過前端開發都知道前端的工作內容是很多的,對于HTML、CSS、Javascript、Image、Flash等各種內容的使用。為了更好提升應用的性能,我們需要對各種資源內容進行不同方面的優化。

    對用戶而言,優化可以讓應用的響應速度加快,加載更加迅速,可以帶來更好的使用體驗。

    對于服務商而言,前端優化能夠減少頁面請求數量,寬帶所占帶寬,有效的節省資源。

    前端優化的內容很多,按照粒度等級劃分可以大致分為兩類:頁面優化級別和代碼級別優化。

    頁面優化主要針對頁面加載環節,包括:HTTP請求數、腳本的無阻塞加載、內聯腳本的位置優化等內容。代碼優化包括:Javascript中的DOM操作優化、CSS選擇符優化、圖片優化以及HTML結構優化等內容。

    代碼級別優化則更關注數據請求,很重要的一條就是減少HTTP請求的數量。一個完整的HTTP請求需要經過路由查找,TCP握手,發送請求,服務器響應和瀏覽器接收等一些列過程。對于小文件,實際下載文件的時間對于整個請求的時間占比很低,因此需要將小文件合并為大文件來傳輸。

    頁面級別:提升頁面加載速度

    加載優化是為了解決頁面內容加載速度受限于網絡帶寬,過于耗時的問題,主要手段有:

    項目打包優化

    Webpack 是一個前端資源加載/打包工具。它將根據模塊的依賴關系進行靜態分析,然后將這些模塊按照指定的規則生成對應的靜態資源。通常我們使用Webpack將多種靜態資源js、css、less 轉換成一個靜態文件,減少了頁面的請求。

    核心概念有:

    Output:告訴 webpack 在哪里輸出它所創建的 bundles,以及如何命名這些文件,默認值為 ./dist。

    Module:Webpack 會從配置的 Entry 開始遞歸找出所有依賴的模塊。

    Chunk:一個 Chunk 由多個模塊組合而成,用于代碼合并與分割。

    Loader:loader 可以將所有類型的文件轉換為 webpack 能夠處理的有效模塊,然后你就可以利用 webpack 的打包能力,對它們進行處理。

    Plugin:被用于轉換某些類型的模塊,而插件則可以用于執行范圍更廣的任務。

    雪碧圖(CSS Sprite)

    CSS雪碧 即CSS Sprite,也有人叫它CSS精靈,是一種CSS圖像合并技術,該方法是將小圖標和背景圖像合并到一張圖片上,然后利用css的背景定位來顯示需要顯示的圖片部分。

    雪碧圖實現的基本原理是把我們從網上用到圖片整合在同一張圖片中,從而可以減少網站HTTP的請求數量。這一張圖片使用CSS background和background-position屬性渲染,

    這意味著我們的標簽變得更加復雜,圖片是在CSS中定義,而非<img>標簽。

    使用雪碧圖有兩個明顯的優點:

    1. 降低網頁圖片內容對服務器的請求次數

    雪碧圖可以合并大多數的背景圖片和小圖標,方便我們在任何位置使用。不同位置的請求只會調用同一個圖片,大大減少頁面對服務器的請求次數,降低服務器的壓力;這樣也可以提高頁面的加載速度,節約服務器的流量。

    1. 提升頁面加載速度

    雪碧圖拼接的圖片尺寸明顯小于所有圖片拼合之前的打小。

    從這兩方面可以明顯對前端請求速度進行優化。

    在HTTP2之后,已經不需要考慮減少請求數,故雪碧圖現在在前端頁面優化性能的意義已經不大。現在更加推薦使用字體圖標,文件很小并且是矢量圖標

    CDN加速

    CDN的全稱是Content Delivery Network,即內容分發網絡。其目的是通過在現有的Internet中增加一層新的CACHE(緩存)層,將網站的內容發布到最接近用戶的網絡”邊緣“的節點,使用戶可以就近取得所需的內容,提高用戶訪問網站的響應速度。從技術上全面解決由于網絡帶寬小、用戶訪問量大、網點分布不均等原因,提高用戶訪問網站的響應速度。

    Cache層技術可以用來消除峰值數據訪問造成的節點設備阻塞。Cache服務器具有緩存功能,絕大部分的網頁對象的重復訪問不需要從原始網站重新傳送文件,只需要通過簡單認證將副本發送即可。緩存服務器的位置通常不輸在用戶端附近,所以可以獲得局域網的響應速度,有效減少廣域寬帶消耗。

    對于提升響應速、節約帶寬、有效減輕源服務器的負載十分有效。

    總結來說CDN對網絡的優化作用主要體現在如下幾個方面: 

    • 解決服務器端的“第一公里”問題  
    • 緩解甚至消除了不同運營商之間互聯的瓶頸造成的影響  
    • 減輕了各省的出口帶寬壓力  
    • 緩解了骨干網的壓力  
    • 優化了網上熱點內容的分布

    gzip壓縮

    Gzip是GNUzip的縮寫,是一個GNU自由軟件的文件壓縮程序,在使用中基本可以壓縮50%的文本文件大小。在說Gzip之前,我們先介紹一個概念,HTTP 壓縮。HTTP 壓縮是一種內置到網頁和網頁客戶端中以改進傳輸速度和帶寬利用率的方式。在使用 HTTP 壓縮的情況下,HTTP 數據在從服務器發送前就已壓縮:兼容的瀏覽器將在下載所需的格式前宣告支持何種方法給服務器;不支持壓縮方法的瀏覽器將下載未經壓縮的數據。

    HTTP 壓縮就是以縮小體積為目的,對 HTTP 內容進行重新編碼的過程。

    Gzip就是HTTP壓縮的經典例題。

    減少文件大小會帶來兩個明顯的好處:

    1. 減少存儲空間
    2. 通過網絡傳輸時可以減少傳輸時間

    Gzip 壓縮背后的原理,是在一個文本文件中找出一些重復出現的字符串、臨時替換它們,從而使整個文件變小。也正是因為這個原理,文件中代碼的重復率越高,Gzip壓縮的效率就越高,使用 Gzip 的收益也就越大。反之亦然。

    代碼級別:減少數據請求次數

    前面我們列舉了在頁面初始加載時的優化方法,然而在某些場景下這還不夠,因為經常會出現頁面展示和使用時,頻繁請求服務來更新信息的場景。

    例如在開發類Excel在線協同系統時,因為單元格業務相互獨立,全屏刷新無法滿足需求。我們只能定時從服務器獲取每個單元格的值,檢測到變化后展示在頁面上。而每個單元格分別調用api獲取內容,就會產生大量網絡請求。大量的請求一方面拖累了加載速度,頁面也會發生卡頓。

    「技術分享」從頁面加載到數據請求,前端頁面性能優化實踐分享

    在這種場景下,WebSocket是一個很好的選擇,通過長鏈接的方式保持與服務器的同步,服務端主動推送更新到客戶端,減少了網絡的開銷。但是WebSocket也有自身的缺點,開發成本高,無論是客戶端還是服務端都需要考慮斷開重連、頻繁推送、資源占用等問題。所以,我們還需要通過優化,盡量減少請求頻率。

    優化思路

    如何減少數據請求數量?我們可以通過請求隊列的方式,對邏輯進行優化。

    「技術分享」從頁面加載到數據請求,前端頁面性能優化實踐分享

    (通過請求隊列優化Web請求)

    經過優化,類Excel在線協同系統獲取數據的邏輯變成了如下的樣子:

    • 當單元格發送請求時,請求先添加ID,并通過ID緩存callback方法,然后進入請求隊列,隊列管理器定時或者根據隊列中請求數量多少像服務端發送請求包。
    • 服務端接收到請求包后批量處理,處理后封裝新的返回包
    • 前端接受到返回包后根據請求的唯一ID,調用對應的callback方法執行,完成單元格的請求

    使用此方法進行優化,優點是顯而易見的:

    • 實現簡單,代碼改動小,原本的ajax請求改為隊列調用即可,請求后的callbak無需修改。服務端添加一個新接口拆分請求即可。
    • 根據實際場景設置請求頻率或者一次請求中數據的數量,兼顧更新頻率和相應次數。

    應用實例

    下面代碼是GETNUMBERFROMSERVER的實現,該函數負責調用服務器的getData接口,傳遞參數,獲取顯示內容并展示在單元格。為了確保異步更新單元格的用戶體驗,這個函數源自SpreadJS的異步函數。

    1. var GetNumberFromServer = function () {
    2. };
    3. GetNumberFromServer.prototype = new GC.Spread.CalcEngine.Functions.AsyncFunction(“GETNUMBERFROMSERVER”, 1, 2);
    4. GetNumberFromServer.prototype.evaluate = function (context, arg1, arg2) {
    5. fetch(“/spread/getData?data=”+arg1)
    6. .then(function(response) {
    7. return response.text();
    8. })
    9. .then(function(text) {
    10. context.setAsyncResult(text);
    11. });
    12. };
    13. GC.Spread.CalcEngine.Functions.defineGlobalCustomFunction(“GETNUMBERFROMSERVER”, new GetNumberFromServer());

    為了減少請求,我們首先需要使用一個緩存對象存放請求數據,定時調用接口處理。

    1. let callStack = {}; //收集請求數據
    2. let callingStack = {}; //緩存正在請求中的數據信息
    3. let callStackCount = 0; //請求數量,當作請求ID,用于區分請求內容
    4. let timingId = 0; //用于判斷當前是否有定時器等待請求中

    然后,我們定義新的隊列化請求方法,代替在函數中直接調用API接口。

    1. // data 請求數據
    2. // context 異步函數context, 網絡請求結束后回調時使用
    3. // callback 回調函數
    4. function stackCall(data, context, callback){
    5. let id = callStackCount++;
    6. callStack[id] = {};
    7. callStack[id].data = data;
    8. callStack[id].context = context;
    9. callStack[id].callback = callback;
    10. if(timingId === 0){ // 同時只有一個定時器
    11. timingId = setTimeout(function(){
    12. callingStack = callStack;
    13. callStack = {};
    14. let newData = “” //合并請求數據,根據實際業務情況整理
    15. for(let cId in callingStack){
    16. newData += (cId + “,” + callingStack[cId].data + “;”);
    17. }
    18. // 發送請求,這里模擬數據,發送什么返回什么
    19. fetch(“/spread/getData?data=” + newData)
    20. .then(function(response) {
    21. return response.text();
    22. })
    23. .then(function(text) {
    24. let resData = newData.split(“;”);
    25. let spread = designer.getWorkbook();
    26. spread.suspendPaint(); //暫定頁面繪制
    27. //解析返回的數據
    28. for(let resId in resData){
    29. if(resData[resId]){
    30. let ress = resData[resId].split(“,”);
    31. // 根據Id,獲取函數的context,調用callback回調
    32. callingStack[ress[0]].callback.call(null, callingStack[ress[0]].context, ress[1])
    33. }
    34. }
    35. spread.resumePaint(); //重啟統一繪制
    36. timingId = 0;
    37. });
    38. }, 1000)
    39. }
    40. }

    最后更新異步函數的實現方式,在函數中調用stackCall堆棧函數,批量調用成功后執行callback回調中的setAsyncResult方法,最終實現業務邏輯。

    1. GetNumberFromServer.prototype.evaluate = function (context, arg1, arg2) {
    2. stackCall(arg1, context, function(context, text){
    3. context.setAsyncResult(text);
    4. })
    5. };

    經過這次優化,當頁面有大量異步請求時,這些請求會放到隊列中,定時統一處理,一次刷新。

    此外,我們還可以使用SpreadJS的doNotRecalculateAfterLoad導入選項,在首次加載時不計算,改用json中原始值;以及calcOnDemand開啟按需計算。進一步優化頁面初始化的速度和體驗。

    1. json.calcOnDemand = true;
    2. spread.fromJSON(json, { doNotRecalculateAfterLoad: true });

    總結

    本文分類介紹了幾種前端性能優化的方法。這些最佳實踐覆蓋了頁面加載和數據請求環節。在文章的后半部分,我們通過類Excel在線協同編輯的實例,詳細介紹了“數據請求隊列化”的實現,希望對您的前端開發有幫助。

    版權聲明:本文內容由互聯網用戶自發貢獻,該文觀點僅代表作者本人。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如發現本站有涉嫌抄襲侵權/違法違規的內容, 請發送郵件至 舉報,一經查實,本站將立刻刪除。

    發表評論

    登錄后才能評論
    国产精品区一区二区免费