国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

XCel 項目總結 - Electron 與 Vue 的性能優化

XUI / 2005人閱讀

摘要:而這里的單元格信息是唯一的,所以直接通過為一個空對象賦值即可。和相關的知識和技巧高亮的列單元格采用展示。在中,被選中的單元格會高亮相應的行和列,以提醒用戶。

XCEL 是一個 Excel 數據清洗工具,其通過可視化的方式讓用戶輕松地對 Excel 數據進行篩選。

XCEL 基于 Electron 和 Vue 2.0 進行開發,充分利用 Electron 多進程任務處理等功能,使其擁有高性能、跨平臺(windows 7+、Mac 和 Linux)的特性。

落地頁:https://xcel.aotu.io/ ???
項目地址:https://github.com/o2team/xcel ???

項目背景

用戶研究的定量研究和輕量級數據處理中,均需對數據進行清洗處理,用以剔除異常數據,保證數據結果的信度和效度。目前因調研數據和輕量級數據的多變性,對輕量級數據清洗往往采取人工清洗,缺少統一、標準的清洗流程,但對于調研和輕量級的數據往往是需要保證數據穩定性的,因此,在對數據進行清洗的時候最好有可以標準化的清洗方式。

特性一覽

基于 Electron 研發并打包成為原生應用,用戶體驗良好;

可視化操作 Excel 數據,支持文件的導入導出;

擁有單列運算邏輯、多列運算邏輯和雙列范圍邏輯三種篩選方式,并且可通過“且”、“或”和“編組”的方式任意組合。

思路與實現

結合用研組的需求,我們利用 Electron 和 Vue 的特性對該工具進行開發。

技術選型

Electron:桌面端跨平臺框架,為 Web 提供了原生接口的權限。打包后的程序兼容 Windows 7 及以上、Mac、Linux 的 32 / 64 位系統。詳情>>

Vue 全家桶:Vue 擁有數據驅動視圖的特性,適合重數據交互的應用。詳情>>

js-xlsx:各種電子表格格式的解析器和生成器。純 JavaScript 實現,適用于 Node.js 和 Web 前端。詳情>>

實現思路

通過 js-xlsx 解析 Excel 文件生成 JSON 格式

根據篩選條件對 JSON 數據進行篩選過濾

將過濾后的 JSON 數據生成 js-xlsx 指定的數據結構

利用 js-xlsx 對轉換后的數據生成 Excel 文件

紙上得來終覺淺,絕知此事要躬行

相關技術

如果對某項技術比較熟悉可略讀/跳過。

Electron Electron 是什么?

Electron 是一個能讓你通過 JavaScript、HTML 和 CSS 構建桌面應用的框架。這些應用能打包到 Mac、Windows 和 Linux 電腦上運行,當然它們也能上架到 Mac 和 Windows 的 app stores。

JavaScript、HTML 和 CSS 都是 Web 語言,這就意味著它們都是組成網站的一部分,瀏覽器(如 Chrome)能將這些代碼轉為可視化圖像。

Electron 是一個框架:Electron 對底層代碼進行抽象和封裝,讓開發者能在此之上構建項目。

為什么它如此重要?

通常來說,桌面應用都需要用每個操作系統對應的原生語言進行開發。這意味著需要擁有 3 個團隊為這個應用編寫 3 個相應的版本。Electron 則允許你通過 web 語言編寫一次即可。

原生(操作系統)語言:用于開發主流操作系統的應用的原生語言如下(大多數情況下):Mac 對應 Objective C、Linux 對應 C、Windows 對應 C++。

它由什么組成?

Electron 結合了 ChromiumNode.js 和用于調用操作系統本地功能的 API(如打開文件窗口、通知、圖標等)。

Chromium:Google 創造的一個開源庫,并用于 Google 的瀏覽器 Chrome。

Node.js(Node):一個用于在服務器運行 JavaScript 的運行時(runtime),它擁有文件系統和網絡的權限(你的電腦也可以是一臺服務器!)。

開發體驗如何?

基于 Electron 的開發,就好像開發一個網頁一樣,而且能夠無縫地 使用 Node。或者說:就好像構建一個 Node app,并通過 HTML 和 CSS 構建界面。另外,你只需為一個瀏覽器(最新的 Chrome)進行設計(即無需考慮兼容性)。

使用內置的 Node:這還不是全部!除了 Node API,你還可以使用托管在 npm 上,超過 350,000 個的模塊。

一個瀏覽器:并非所有瀏覽器都提供一致的樣式,因此 web 設計師和開發者時常不得不花費更多的精力去讓一個網站在不同的瀏覽器上看起來一致。

最新的 Chrome:可使用超過 90% 的 ES2015 特性和其它很酷的特性(如 CSS 變量)。

兩個進程(重點)

Electron 有兩個種進程:『主進程』和『渲染進程』。有些模塊只能工作在其中一個進程上,而有些則能工作在兩個進程上。主進程更多地充當幕后角色,而渲染進程則是應用的每個窗口。
PS:可通過任務管理器(PC)/活動監視器(Mac)查看進程的相關信息。

模塊:Electron 的 API 是根據它們的功能進行分組。例如:dialog 模塊擁有所有原生 dialog 的 API,如打開文件、保存文件和彈窗。

主進程

主進程,通常是一個命名為 main.js 的文件,該文件是每個 Electron 應用的入口。它控制了應用的生命周期(從打開到關閉)。它能調用原生元素和創建新的(多個)渲染進程,而且整個 Node API 是內置其中的。

調用原生元素:打開 diglog 和其它操作系統交互均是資源密集型操作(注:出于安全考慮,渲染進程是不能直接調用本地資源的),因此都需要在主進程完成。

渲染進程

渲染進程是應用的一個瀏覽器窗口。與主進程不同,它能存在多個(注:一個 Electron 應用只能有一個主進程)并且是相互獨立的。它們也能是隱藏的。它通常被命名為 index.html。它們就像典型的 HTML 文件,但在 Electron 中,它們能獲取完整的 Node API 特性。因此,這也是它與其它瀏覽器不同的地方。

相互獨立:每個渲染進程都是獨立的,這意味著就算它們某個崩潰了,也不會影響其余的渲染進程。

隱藏的:你可以設置一個窗口是隱藏的,然后讓它只在背后執行代碼(?)。

把它們想象成這樣

在 Chrome(或其它瀏覽器)中的每個標簽頁(tab) 和其內的頁面,就好比 Electron 中的一個多帶帶渲染進程。如果你關閉所有標簽頁,Chrome 依然存在,這好比 Electron 的主進程,而且你能打開一個新的窗口或關閉這個應用。

注:一般情況下,在 Chrome 瀏覽器中,一個標簽頁(tab)中的頁面(即除了瀏覽器本身部分,如搜索框、工具欄等)就是一個渲染進程。

相互通訊

盡管主進程和渲染進程都有各自的任務,但它們之間也有需要協同完成的任務。因此它們之間需要通訊。IPC就為此而生,它提供了進程間的通訊。但它只能在主進程與渲染進程之間傳遞信息。

IPC:主進程和渲染進程都有一個 IPC 模塊。

匯成一句話

Electron 應用就像 Node 應用,它也依賴一個 package.json 文件。該文件定義了哪個文件作為主進程,并因此讓 Electron 知道從何啟動你的應用。然后主進程能創建渲染進程,并能使用 IPC 讓兩者間進行消息傳遞。

至此,Electron 的基礎部分介紹完畢。該部分是基于我之前翻譯的一篇文章《Essential Electron》,譯文可點擊 這里。

-----

Vue 全家桶

目前,該工具應用了 Vue、Vuex、Vuex-router。在工具基本定型階段,由 1.x 升級到了 2.0 (Vuex 暫未升級)。

為什么選擇 Vue

對于我來說:

簡單易用,一般使用只需看官方文檔。

數據驅動視圖,所以基本不用操作 DOM 了。

框架的存在是為了幫助我們應對復雜度。

全家桶的好處是:對于一般場景,我就不需要考慮用哪些個庫(插件)。

Vue 1.x -> Vue 2.0 的版本遷移用 vue-migration-helper 即可分析出大部分需要更改的地方。

網上已經有很多關于 Vue 的信息了。至此,Vue 部分介紹完畢。

js-xlsx

該庫支持各種電子表格格式的解析和生成。它由純 JavaScript 實現,適用于前端和 Node。詳情>>

支持讀入的格式有:

Excel 2007+ XML Formats (XLSX/XLSM)

Excel 2007+ Binary Format (XLSB)

Excel 2003-2004 XML Format (XML "SpreadsheetML")

Excel 97-2004 (XLS BIFF8)

Excel 5.0/95 (XLS BIFF5)

OpenDocument Spreadsheet (ODS)

支持寫的格式有:

XLSX

CSV (and general DSV)

JSON and JS objects (various styles)

只要能提供讀(解析)和寫,剩下的就是靠 JavaScript 處理解析出來的數據(JSON)了。目前該庫提供了 sheet_to_json 方法,該方法能將讀入的 Excel 數據轉為 JSON 格式。由于導出時需要提供特定的 JSON 格式,因此這部分需要我們自己實現。

更多關于 Excel 在 JavaScript 中處理的知識可關注:凹凸實驗室的《Node讀寫Excel文件探究實踐》。但該文章存在兩處問題(均在 js-xlsx 實戰的導出表格部分):

生成頭部時,Excel 的列信息簡單地通過 String.fromCharCode(65+j) 生成,但列大于 26 時就會出現問題。這個問題會在后面章節中給出解決方案;

轉換成 worksheet 需要的結構處,出現邏輯性錯誤,并且會導致嚴重的性能問題。邏輯問題在此不講述,我們講下性能問題:
ECMAScript 的不斷更新,讓 JavaScript 更加強大和易用。盡管如此,我們還是要做到『物盡所用』,而不要『大材小用』,否則會得到反效果。這里導致性能問題的正是 Object.assign() 方法,該方法可以把任意多個的源對象自身的可枚舉屬性拷貝給目標對象,然后返回目標對象。由于該方法自身的實現機制,會在這里產生大量的冗余操作。而這里的單元格信息是唯一的,所以直接通過 forEach 為一個空對象賦值即可。提升 N 倍性能的同時,也把邏輯性錯誤解決了。

原來的:

var result = 某數組.reduce((prev, next) => Object.assign({}, prev, {[next.position]: {v: next.v}}), {});

改為:

var result = 某數組.forEach((v, i) => data[v.position]= {v: v.v})

實踐是檢驗真理的唯一標準
在理解上述知識的前提下,下面就談談一些在實踐中總結出來的技巧、難點和重點

CSS、JavaScript 和 Electron 相關的知識和技巧 高亮 table 的列

Excel 單元格采用 table 展示。在 Excel 中,被選中的單元格會高亮相應的『行』和『列』,以提醒用戶。在該應用中也有做相應處理,橫向高亮采用 tr:hover 實現,而縱向呢?這里所采用的一個技巧是:

假設 HTML 結構如下:

div.container
  table
    tr
      td

CSS 代碼如下:

.container { overflow:hidden; }
td { position: relative; }
td:hover::after { 
  position: absolute; 
  left: 0; 
  right: 0; 
  top: -1個億px; // 小目標達成,不過是負的?
  bottom: -1個億px; 
  z-index: -1; // 避免遮住自身和同列 td 的內容、border 等
}
斜分割線

如圖:

分割線可以通過 ::after/::before 偽類元素實現一條直線,然后通過 transform:rotate(); 旋轉特定角度實現。但這種實現的一個問題是:由于寬度是不定的,因此需要通過 JavaScript 運算才能得到準確的對角分割線。

因此,這里可以通過 CSS 線性漸變 linear-gradient(to top right, transparent, transparent calc(50% - .5px), #d3d6db calc(50% - .5px), #d3d6db calc(50% + .5px), transparent calc(50% + .5px)) 實現。無論寬高如何變,依然妥妥地自適應。

Excel 的列轉換

Excel 的列需要用『字母』表示,但不能簡單地通過 String.fromCharCode() 實現,因為當超出 26列 時會產生問題(如:第 27 列,String.fromCharCode(65+26) 得到的是 [,而不是 AA)。因此,這需要通過『十進制和26進制轉換』算法來實現。

// 將指定的自然數轉換為26進制表示。映射關系:[0-25] -> [A-Z]。
function getCharCol(n) {
    let temCol = "",
        s = "",
        m = 0
    while (n >= 0) {
        m = n % 26 + 1
        s = String.fromCharCode(m + 64) + s
        n = (n - m) / 26
    }
    return s
}
// 將指定的26進制轉換為自然數。映射關系:[A-Z] ->[0-25]。
function getNumCol(s) {
    if (!s) return 0
    let n = 0
    for (let i = s.length - 1, j = 1; i >= 0; i-- , j *= 26) {
        let c = s[i].toUpperCase()
        if (c < "A" || c > "Z") return 0
        n += (c.charCodeAt() - 64) * j
    }
    return n - 1
}
為 DOM 的 File 對象增加了 path 屬性

Electron 為 File 對象額外增了 path 屬性,該屬性可得到文件在文件系統上的真實路徑。因此,你可以利用 Node 為所欲為?。應用場景有:拖拽文件后,通過 Node 提供的 File API 讀取文件等。

支持常見的編輯功能,如粘貼和復制

Electron 應用在 MacOS 中默認不支持『復制』『粘貼』等常見編輯功能,因此需要為 MacOS 顯式地設置復制粘貼等編輯功能的菜單欄,并為此設置相應的快捷鍵。

// darwin 就是 MacOS
if (process.platform === "darwin") {
    var template = [{
      label: "FromScratch",
      submenu: [{
        label: "Quit",
        accelerator: "CmdOrCtrl+Q",
        click: function() { app.quit(); }
      }]
    }, {
      label: "Edit",
      submenu: [{
        label: "Undo",
        accelerator: "CmdOrCtrl+Z",
        selector: "undo:"
      }, {
        label: "Redo",
        accelerator: "Shift+CmdOrCtrl+Z",
        selector: "redo:"
      }, {
        type: "separator"
      }, {
        label: "Cut",
        accelerator: "CmdOrCtrl+X",
        selector: "cut:"
      }, {
        label: "Copy",
        accelerator: "CmdOrCtrl+C",
        selector: "copy:"
      }, {
        label: "Paste",
        accelerator: "CmdOrCtrl+V",
        selector: "paste:"
      }, {
        label: "Select All",
        accelerator: "CmdOrCtrl+A",
        selector: "selectAll:"
      }]
    }];
    var osxMenu = menu.buildFromTemplate(template);
    menu.setApplicationMenu(osxMenu);
}
更貼近原生應用

Electron 的一個缺點是:即使你的應用是一個簡單的時鐘,但它也不得不包含完整的基礎設施(如 Chromium、Node 等)。因此,一般情況,打包后的程序至少會達到幾十兆(根據系統類型進行浮動)。當你的應用越復雜,就越可以忽略這部分了。

眾所周知,頁面的渲染難免會導致『白屏』,而且這里采用了 Vue 框架,情況就更加糟糕了。另外,Electron 應用也避免不了『先打開瀏覽器,再渲染頁面』的步驟。下面提供幾種方法來減輕這種情況,以讓程序更貼近原生應用。

指定 BrowserWindow 的背景顏色;

先隱藏窗口,直到頁面加載后再顯示;

保存窗口的尺寸和位置,以讓程序下次被打開時,依然保留的同樣大小和出現在同樣的位置上。

對于第一點,若程序的背景不是純白(#fff)的,那么可指定窗口的背景顏色與其一致,以避免突變。

mainWindow = new BrowserWindow({
    title: "XCel",
    backgroundColor: "#f5f5f5",
};

對于第二點,由于 Electron 本質是一個瀏覽器,需要加載非網頁部分的資源。因此,我們可以先隱藏窗口。

var mainWindow = new BrowserWindow({
    title: "ElectronApp",
    show: false,
};

等到渲染進程開始渲染頁面的那一刻,在 ready-to-show 的回調函數中顯示窗口。

mainWindow.on("ready-to-show", function() {
    mainWindow.show();
    mainWindow.focus();
});

對于第三點,我并沒有實現,原因如下:

用戶一般是根據當時的情況對程序的尺寸和位置進行調整,即視情況而定。

以上是我個人臆測,主要是我懶?。

其實現方式,可參考《4 must-know tips for building cross platform Electron apps》。

如何在渲染進程調用原生彈框?

在渲染進程中調用原本專屬于主進程中的 API (如彈框)的方式有兩種:

IPC 通訊模塊:先在主進程通過 ipcMain 進行監聽,然后在渲染進程通過 ipcRenderer 進行觸發;

remote 模塊:該模塊提供了一種在渲染進程(網頁)和主進程之間進行進程間通訊(IPC)的簡便途徑。

對于第一種,有需要就在評論區留言;

對于第二種, 在渲染進程中,運行以下代碼即可:

const remote = require("electron").remote

remote.dialog.showMessageBox({
    type: "question",
    buttons: ["不告訴你", "沒有夢想"],
    defaultId: 0,
    title: "XCel",
    message: "你的夢想是什么?"
}

自動更新

如果 Electron 應用沒有了自動更新的功能,那么意味著用戶想體驗你新開發的功能或用上修復 Bug 后的新版本,只能靠自己主動地去官網下載,這無疑是糟糕的體驗。Electron 提供的 autoUpdater 模塊可實現自動更新功能,該模塊提供了第三方框架 Squirrel 的接口,但 Electron 目前只內置了 Squirrel.Mac,且它與 Squirrel.Windows(需要額外引入)的處理方式也不一致(在客戶端與服務器端兩方面),因此如果剛接觸該模塊,會發現處理起來相對比較繁瑣。具體可以參考我的一篇譯文《Electron 自動更新的完整教程(Windows 和 OSX)》。

目前 Electron 的 autoUpdater 模塊不支持 Linux 系統。

另外,XCel 目前并沒有采用 autoUpdater 模塊實現自動更新功能,而是利用 Electron 的 DownloadItem 模塊實現。而服務器端則采用 Nuts。

為 Electron 應用生成 Windows 安裝包

通過 electron-builder 即可直接生成常見的 MacOS 安裝包,但它生成的 Windows 的安裝包卻略顯簡潔。


Mac 常見的安裝模式,將“左側的應用圖標”拖拽到“右側的 Applications”即可

通過 electron-builder 生成的 Windows 安裝包與我們在 Windows 上常見的軟件安裝界面不太一樣,它沒有安裝向導和點擊“下一步”的按鈕,只有一個安裝時的 gif 動畫(默認的 gif 動畫如下圖,當然你也可以指定特定的 gif 動畫),因此也就沒有讓用戶選擇安裝路徑等權利。


Windows 安裝時 默認顯示的 gif 動畫

如果你想為打包后的 Electron 應用(即通過 electron-packager/electron-builder 生成的 、可直接運行的程序目錄)生成需要點擊“下一步”和可讓用戶指定安裝路徑的常見安裝包,可以通過 NSIS 程序,具體可看這篇教程 《[教學]只要10分鐘學會使用 NSIS 包裝您的桌面軟體–安裝程式打包。完全免費。》。

NSIS(Nullsoft Scriptable Install System)是一個開源的 Windows 系統下安裝程序制作程序。它提供了安裝、卸載、系統設置、文件解壓縮等功能。這如其名字所指出的那樣,NSIS 是通過它的腳本語言來描述安裝程序的行為和邏輯的。NSIS 的腳本語言和通常的編程語言有類似的結構和語法,但它是為安裝程序這類應用所設計的。

至此,CSS、JavaScript 和 Electron 相關的知識和技巧 部分闡述完畢。

性能優化

下面談談『性能優化』,這部分涉及到運行效率內存占用量
注:以下內容均基于 Excel 樣例文件(數據量為:1913 行 x 180 列)得出的結論。

執行效率和渲染的優化 Vue 性能真的好?

Vue 一直標榜著自己性能優異,但當數據量上升到一定量級時(如 1913 x 180 ≈ 34 萬個數據單元),會出現嚴重的性能問題(不做相應優化的前提下)。

如直接通過列表渲染 v-for 渲染數據時,會導致程序卡死。
答:通過查閱相關資料可得(猜測), v-for 是通過一條條數據在構建后插入 DOM 的,這對于數據量較大時,無疑會造成嚴重的性能問題。

當時,我想到了兩種解決思路:

Vue 是數據驅動視圖的,對數據分段 push,即將一個龐大的任務分割為 N 份。

自己拼接 HTML 字符串,再通過 innerHTML 一次性插入。

最終,我選擇了第二條,理由是:

性能最佳,因為每次執行數據過濾時,Vue 都要進行 diff,性能不佳。

更符合當前應用的需求:純展示且無需動畫過渡等。

實現更簡單

將原本繁重的 DOM 操作轉移到了 JavaScript 的拼接字符串后,性能得到了很大提升(不會導致程序卡死而渲染不出視圖)。這種實現原理難道不就是 Vue、React 等框架解決的問題之一嗎?只不過框架考慮的場景更廣,有些地方需要我們自己根據實際情況進行優化而已。

在瀏覽器當中,JavaScript 的運算在現代的引擎中非常快,但 DOM 本身是非常緩慢的東西。當你調用原生 DOM API 的時候,瀏覽器需要在 JavaScript 引擎的語境下去接觸原生的 DOM 的實現,這個過程有相當的性能損耗。所以,本質的考量是,要把耗費時間的操作盡量放在純粹的計算中去做,保證最后計算出來的需要實際接觸真實 DOM 的操作是最少的。 —— 《Vue 2.0——漸進式前端解決方案》

當然,由于 JavaScript 天生單線程,即使執行數速度再快,也會導致頁面有短暫的時間拒絕用戶的輸入。此處可通過 Web Worker 或其它方式解決,這也將是我們后續講到的問題。

也有網友提供了優化大量列表的方法:https://clusterize.js.org/。 但在這里我并沒有采用此方式。

強大的 GPU 加速

插入 DOM 后,又會出現了另外一個問題:滾動會很卡。猜想這是渲染問題,畢竟 34 萬個單元格同時存在于界面中。

添加 transform: translate3d(0, 0, 0) / translateZ(0) 屬性啟動 GPU 渲染,即可解決這個渲染性能問題。再次感嘆該屬性的強大。?

后來,考慮到用戶并不需要查看全部數據,只需展示部分數據讓用戶進行參考即可。我們對此只渲染前 30/50 行數據。這樣即可提升用戶體驗,也能進一步優化性能(又是純屬臆測)。

記得關閉 Vuex 的嚴格模式

另外,由于自己學藝不精和粗心大意,忘記在生產環境關閉 Vuex 的『嚴格模式』。
Vuex 的嚴格模式要在生產中關閉,否則會對 state 樹進行一個深觀察 (deep watch),產生不必要的性能損耗。也許在數據量少時,不會注意到這個問題。

我當時的情況是:導入 Excel 數據后,再進行交互(涉及 Vuex 的讀寫操作),則需要等幾秒才會響應,而直接通過純 DOM 監聽的事件則無此問題。由此,判斷出是 Vuex 問題。

const store = new Vuex.Store({
  // ...
  strict: process.env.NODE_ENV !== "production"
})
多進程!!!

前面說道,JavaScript 天生單線程,即使再快,對于需要處理數據量較大的情況,也會出現拒絕響應的問題。因此需要 Web Worker 或類似的方案去解決。

在這里我不選擇 Web worker 的原因有如下幾點:

有其它更好的替代方案:一個主進程能創建多個渲染進程,通過 IPC 即可進行數據交互;

Electron 不支持 Web Worker!

Electron 作者在 2014.11.7 在《state of web worker support?》 issue 中回復了以下這一段:

Node integration doesn"t work in web workers, and there is no plan to do. Workers in Chromium are implemented by starting a new thread, and Node is not thread safe. Back in past we had tried to add node integration to web workers in Atom, but it crashed too easily so we gave up on it.

因此,我們最終采用了創建一個新的渲染進程 background process 進行處理數據。由 Electron 章節可知,每個 Electron 渲染進程是獨立的,因此它們不會互相影響。但這也帶來了一個問題:它們不能相互通訊?

錯!下面有 3 種方式進行通訊:

Storage API:對某個標簽頁的 localStorage/sessionStorage 對象進行增刪改時,其他標簽頁能通過 window.storage 事件監聽到。

IndexedDB:IndexedDB 是一個為了能夠在客戶端存儲可觀數量的結構化數據,并且在這些數據上使用索引進行高性能檢索的 API。

通過主進程作為中轉站:設主界面的渲染進程是 A,background process 是 B,那么 A 先將 Excel 數據傳遞到主進程,然后主進程再轉發到 B。B 處理完后再原路返回,具體如下圖。當然,也可以將數據存儲在主進程中,然后在多個渲染進程中使用 remote 模塊來訪問它。

該工具采用了第三種方式的第一種情況:

1、主頁面渲染進程 A 的代碼如下:

//①
ipcRenderer.send("filter-start", {
    filterTagList: this.filterTagList,
    filterWay: this.filterWay,
    curActiveSheetName: this.activeSheet.name
})

// ⑥ 在某處接收 filter-response 事件
ipcRenderer.on("filter-response", (arg) => {
    // 得到處理數據
})

2、作為中轉站的主進程的代碼如下:

//②
ipcMain.on("filter-start", (event, arg) => {
    // webContents 用于渲染和控制 web page
    backgroundWindow.webContents.send("filter-start", arg)
})

// ⑤ 用于接收返回事件
ipcMain.on("filter-response", (event, arg) => {
    mainWindow.webContents.send("filter-response", arg)
})

3、處理繁重數據的 background process 渲染進程 B 的代碼如下:

// ③
ipcRenderer.on("filter-start", (event, arg) => {
    // 進行運算
    ... 
    
    // ④ 運算完畢后,再通過 IPC 原路返回。主進程和渲染進程 A 也要建立相應的監聽事件
    ipcRenderer.send("filter-response", {
        filRow: tempFilRow
    })
})

至此,我們將『讀取文件』、『過濾數據』和『導出文件』三大耗時的數據操作均轉移到了 background process 中處理。

這里,我們只創建了一個 background process,如果想要做得更極致,我們可以新建『CPU 線程數- 1 』 個的 background process 同時對數據進行處理,然后在主進程對處理后數據進行拼接,最后再將拼接后的數據返回到主頁面的渲染進程。這樣就可以充分榨干 CPU 了。當然,在此我不會進行這個優化。

不要為了優化而優化,否則得不償失。 —— 某網友

內存占有量過大

解決了執行效率和渲染的問題,發現也存在內存占用量過大的問題。當時猜測是以下幾個原因:

三大耗時操作均放置在 background process 處理。在通訊傳遞數據的過程中,由于不是共享內存(因為 IPC 是基于 Socket 的),導致出現多份數據副本(在寫該篇文章時才有了這相對確切的答案)。

Vuex 是以一個全局單例的模式進行管理,但它會是不是對數據做了某些封裝,而導致性能的損耗呢?

由于 JavaScript 目前不具有主動回收資源的能力,所以只能主動對閑置對象設置為 null,然后等待 GC 回收。

由于 Chromium 采用多進程架構,因此會涉及到進程間通信問題。Browser 進程在啟動 Render 進程的過程中會建立一個以 UNIX Socket 為基礎的 IPC 通道。有了 IPC 通道之后,接下來 Browser 進程與 Render 進程就以消息的形式進行通信。我們將這種消息稱為 IPC 消息,以區別于線程消息循環中的消息。

——《Chromium的IPC消息發送、接收和分發機制分析》

定義:為了易于理解,以下『Excel 數據』均指 Excel 的全部有效單元格轉為 JSON 格式后的數據。

最容易處理的無疑是第三點,手動將不再需要的變量及時設置為 null。但這效果并不明顯。

后來,通過系統的『活動監視器』對該工具的每階段(打開時、導入文件時、篩選時和導出時)進行粗略的內存分析,得到以下報告(之前分析的、未作修改):

---------------- S:報告分割線 ----------------
經觀察,主要耗內存的是頁面進程。下面通過截圖說明:
PID 15243 是主進程
PID 15246 是頁面渲染進程
PID 15248 是 background 渲染進程

a、首次啟動程序時(第 4 行是主進程;第 1 行是頁面渲染進程;第 3 行是 background 渲染進程 )

b、導入文件(第 5 行是主進程;第 2 行是頁面渲染進程;第 4 行是 background 渲染進程 )

c、篩選數據(第 4 行是主進程;第 1 行是頁面渲染進程;第 3 行是 background 渲染進程 )

由于 JS 目前不具有主動回收資源的功能,所以只能主動將對象設置為 null,然后等待 GC 回收。

因此,經過一段時間等待后,內存占用如下:
d、一段時間后(第 4 行是主進程;第 1 行是頁面渲染進程;第 3 行是 background 渲染進程 )

由上述可得,頁面渲染進程由于頁面元素和 Vue 等 UI 相關資源是固定的,占用內存較大且不能回收。主進程占用資源也不能得到很好釋放,暫時不知道原因,而 background 渲染進程則較好地釋放資源。

---------------- E:報告分割線 ----------------

根據報告,初步得出的結論是 Vue 和通訊時占用資源較大。

根據該工具的實際應用場景:由于 Excel 數據只在『導入』和『過濾后』兩個階段需要展示,而且展示的只是通過 JavaScript 拼接的 HTML 字符串構成的 DOM 而已。因此將表格數據放置在 Vuex 中,有點濫用資源的嫌疑。

另外,在 background process 中也有存有一份 Excel 數據副本。因此,索性只在 background process 存儲一份 Excel 數據,然后每當數據變化時,通過 IPC 讓 background process 返回拼接好的 HTML 字符串即可。這樣一來,內存占有量立刻下降許多。而且這也是一個一舉多得的優化:

字符串拼接操作也轉移到了 background process,頁面的渲染進程進一步減少耗時的操作;

內存占有量大大減小,響應速度也得到了提升。

其實,這也有點像 Vuex 的『全局單例模式管理』,一份數據就好。

當然,對于 Excel 的基本信息,如行列數、SheetName、標題組等均依然保存在 Vuex。

優化后的內存占有量如下圖。與上述報告的第三張圖相比(同一階段),內存占有量下降了 44.419%:

另外,對于不需要響應的數據,可通過 Object.freeze() 凍結起來。這也是一種優化手段。但該工具目前并沒有應用到。

至此,優化部分也闡述完畢了!

該工具目前是開源的,歡迎大家使用或推薦給用研組等有需要的人。

你們的反饋(可提交 issues / pull request)能讓這個工具在使用和功能上不斷完善。

最后,感謝 LV 在產品規劃、界面設計和優化上的強力支持。全文完!

感謝您的閱讀,本文由 Jc 原創提供。如若轉載,請注明出處:凹凸實驗室(https://aotu.io/notes/2016/11...)

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/91191.html

相關文章

  • Hola~ 一款基于Electron聊天軟件

    摘要:前言本項目旨在從零到壹,制作一款界面精美的聊天軟件。因為本人是開發,設計功底欠缺,所以軟件設計的有點丑,如果有大神有更好的,歡迎。 Hola 前言 本項目旨在從零到壹,制作一款界面精美的聊天軟件。 Github 地址因為已工作,所以可能沒有多少時間來繼續跟進這個項目了,項目可優化的點已在下文列出,歡迎大家 Fork 或 Star。 ps: 征 logo 一枚。因為本人是開發,設計功底...

    Kaede 評論0 收藏0
  • 前端每周清單第 43 期:2017 JavaScript 回顧、Rust WebAssembly

    摘要:楊冀龍是安全焦點民間白帽黑客組織核心成員,被浪潮之巔評為中國新一代黑客領軍人物之一他在本文中依次分享了對于黑客的定義如何從黑客成為一名安全創業者技術創業踩過的坑給技術創業者建議等內容。 showImg(https://segmentfault.com/img/remote/1460000012377230?w=1240&h=796); 前端每周清單專注前端領域內容,以對外文資料的搜集為...

    xorpay 評論0 收藏0
  • 前端文檔收集

    摘要:系列種優化頁面加載速度的方法隨筆分類中個最重要的技術點常用整理網頁性能管理詳解離線緩存簡介系列編寫高性能有趣的原生數組函數數據訪問性能優化方案實現的大排序算法一怪對象常用方法函數收集數組的操作面向對象和原型繼承中關鍵詞的優雅解釋淺談系列 H5系列 10種優化頁面加載速度的方法 隨筆分類 - HTML5 HTML5中40個最重要的技術點 常用meta整理 網頁性能管理詳解 HTML5 ...

    jsbintask 評論0 收藏0
  • 前端文檔收集

    摘要:系列種優化頁面加載速度的方法隨筆分類中個最重要的技術點常用整理網頁性能管理詳解離線緩存簡介系列編寫高性能有趣的原生數組函數數據訪問性能優化方案實現的大排序算法一怪對象常用方法函數收集數組的操作面向對象和原型繼承中關鍵詞的優雅解釋淺談系列 H5系列 10種優化頁面加載速度的方法 隨筆分類 - HTML5 HTML5中40個最重要的技術點 常用meta整理 網頁性能管理詳解 HTML5 ...

    muddyway 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<