菜单

Vue笔记六:Vue项目标属性优化之路

2019年1月20日 - jQuery

XCel 项目统计:Electron 与 Vue 的性能优化

2017/03/01 · 基本功技术 ·
Javascript,
算法

正文小编: 伯乐在线
刘健超-J.c
。未经小编许可,禁止转发!
欢迎参预伯乐在线 专辑作者

XCEL 是由京东用户体验设计部凹凸实验室推出的一个 Excel
数据清洗工具,其经过可视化的法门让用户轻松地对 Excel 数据开展筛选。

XCEL 基于 Electron 和 Vue 2.x,它不只跨平台(windows 7+、Mac 和
Linux),而且充足利用 Electron 多进度职责处理等功能,使其属性优良。

落地页:https://xcel.aotu.io/ ✨✨✨
花色地址:https://github.com/o2team/xcel ✨✨✨

Vue笔记六:Vue项目的性能优化之路

自身方今也时不时面试外包同事。面试的时候,总会有个问题,“你说一下性质优化的手腕”。百分之八十的人都会说,压缩js和css之类的。显明那些都是必须做的,而且早已根本不是主要的性质优化的关键点。固然您只会说这个,只可以表明您是个过时的前端工程师。

特性优化进度中,大家需要直面的越多是DMS解析进度,服务器缓存和浏览器缓存机制。

品种背景

用户切磋的定量商讨和轻量级数据处理中,均需对数码进行保洁处理,以剔除非常数据,保障数据结果的信度和效度。近期因调研数据和轻量级数据的多变性,对轻量级数据清洗往往拔取人工清洗,贫乏统一、标准的清洗流程,但对此调研和轻量级的数目往往是急需有限支撑数据稳定性的,因而,在对数据开展清洗时最好有标准的清洗方法。

gzip压缩

在所有的web前端项目,静态资源为主都位居cdn上,gzip的压缩是丰盛要求的,它一直改动了js文件的深浅,收缩两到三倍。

参考加速nginx:
开启gzip和缓存
,nginx的gzip配置万分不难,在您对号入座的域名底下,添加下边的配备,重启服务即可。gzip_comp_level的值大于2的时候并不明确,提议设置在1要么2之间。

# 开启gzip
gzip on;
# 启用gzip压缩的最小文件,小于设置值的文件将不会压缩
gzip_min_length 1k;
# gzip 压缩级别,1-10,数字越大压缩的越好,也越占用CPU时间,后面会有详细说明
gzip_comp_level 2;
# 进行压缩的文件类型。javascript有多种形式。其中的值可以在 mime.types 文件中找到。
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
# 是否在http header中添加Vary: Accept-Encoding,建议开启
gzip_vary on;
# 禁用IE 6 gzip
gzip_disable "MSIE [1-6]\.";

特征一览

服务器缓存

为了加强服务器获取数据的快慢,nginx缓存着静态资源是丰硕须求的。即使是测试服务器对html应该不设置缓存,而js等静态资源条件因为文件尾部会添加一个hash值,那可以使得已毕缓存的决定。

location ~* ^.+\.(ico|gif|jpg|jpeg|png)$ { 
  access_log   off; 
  expires      30d;
}
location ~* ^.+\.(css|js|txt|xml|swf|wav)$ {
  access_log   off;
  expires      24h;
}
location ~* ^.+\.(html|htm)$ {
  expires      1h;
}

思路与完毕

据悉用研组的急需,利用 Electron 和 Vue 的性状对该工具举办付出。

浏览器缓存

浏览器缓存是通过html的头文件中的meta来支配。http-equiv是一个特意针对http的头文件,可以向浏览器传回一些管用的音讯。与之相应的content,是逐一参数的变量值。

技巧选型

HTTP 1.0

在HTTP1.0中通过Pragma控制页面缓存,可以安装为Pragmano-cache。在不让浏览器或中等缓存服务器缓存页面的情状下,平常设置的值为no-cache,不过那个值不那样有限支持,经常还添加Expires置为0来完成目标。Expires可以用于设定网页的到期时间。一旦网页过期,必须到服务器上再一次传输获取新的页面信息。PS:内容必须采纳GMT的光阴格式。

<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">

落成思路

  1. 透过 js-xlsx 将 Excel 文件分析为 JSON 数据
  2. 按照筛选标准对 JSON 数据举办筛选过滤
  3. 将过滤后的 JSON 数据转换成 js-xlsx 指定的数据结构
  4. 运用 js-xlsx 对转移后的数目生成 Excel 文件

纸上得来终觉浅,绝知此事要躬行

HTTP 1.1

在HTTP1.1中通过Cache-Control决定页面缓存,可以设置为no-cacheprivateno-storemax-agemust-revalidate等,默认为private。

<meta http-equiv="Cache-Control" content="no-cache">

连锁技能

假使对某项技术相比熟识,则可略读/跳过。

Last-Modified和Etags

Last-Modified服务器端文件响应头,描述最终修改时间。当浏览器再一次开展呼吁时,会向服务器传送If-Modified-Since报头,询问时间点之后资源是否被涂改过,从而区分200和304的呼吁状态码,304则选用浏览器缓存。

Etags差距的是,ETag是基于实体内容生成一段hash字符串,是标识资源的情景。它由服务端暴发来判定文件是否有更新。

参考资料:

Electron

JS分包

前方说的两部分都足以说是偏后端的活,即便真的此前端方面考虑,大家可能会含有入手。正因为vue的脚手架搭建的项目,webpack的安顿当中就富含了压缩js,css和html的收缩。所以,当大家的单页面越做越大的气象下,首要的一步就是包括。

vue官方称gzip压缩后唯有20kb,可是你平凡的打包格局也有100kb,再增加你自己的逻辑代码,全体包的体积也挺大的。直接影响首屏页面加载的功用。上边介绍一下二种含有的主意:

Electron 是什么?

Electron 是一个方可用 JavaScript、HTML 和 CSS
构建桌面应用程序的。那一个应用程序能打包到 Mac、Windows 和 Linux
系统上运行,也能上架到 Mac 和 Windows 的 App Store。

vue,vuex和vue-router

在webpack配置文件中external设置,把那多个场用包排除那一个操作,重即使把那多个包从vendor.js分开。

最后当然须要在html标签上添加上额外cdn的link或者script。

干什么它如此重大?

普普通通来说,每个操作系统的桌面应用都由个其他原生语言举行编制,这代表须求3 个集团分别为该使用编写相应版本。而 Electron 则允许你用 Web
语言编写两次即可。

DLL打包

那种打包格局更加引用webpack官方的DllPluginDllReferencePlugin。DllPlugin会生成一个dll包的代码指纹manifest,管理额外的包裹。而在项目转移的进度中,DllReferencePlugin会参考manifest的始末去打包。额外生成的js文件应当被放置在vue项目标文件当中的static文件夹底下,以便于代码计划。

参考PaicFE/vue-multi中的配置文件webpack.dll.config.js的写法。

它由什么组成?

Electron 结合了 ChromiumNode.js 和用于调用操作系统本地成效的
API(如打开文件窗口、布告、图标等)。

图片 1

预加载

预加载技术(prefetch)是在用户需求前我们就将所需的资源加载落成,不是负有浏览器都协助,紧假如Chrome浏览器。

DNS prefetch
分析那一个页面需求的资源各处的域名,浏览器空闲时提前将这一个域名转化为 IP
地址,真正请求资源时就避免了上述那个进程的时光。—-HTML5
prefetch

鉴于域名转换成为IP的经过是更加耗时的一个历程,DNS
prefetch可以减掉这一部分的时间。

<meta http-equiv='x-dns-prefetch-control' content='on'>
<link rel='dns-prefetch' href='http://g-ecx.images-amazon.com'>
<link rel='dns-prefetch' href='http://z-ecx.images-amazon.com'>
<link rel='dns-prefetch' href='http://ecx.images-amazon.com'>
<link rel='dns-prefetch' href='http://completion.amazon.com'>
<link rel='dns-prefetch' href='http://fls-na.amazon.com'>

预加载也可以对某个静态资源起到专门的效劳。

<link rel='subresource' href='libs.js'>

预渲染(pre-rendering)是以此页面会提前加载好用户即将访问的下一个页面。

<link rel='prerender' href='http://www.pagetoprerender.com'>

付出体验怎样?

依据 Electron 的开支就如在开发网页,而且可以无缝地 使用
Node
。或者说:在构建一个 Node 应用的同时,通过 HTML 和 CSS
构建界面。别的,你只需为一个浏览器(最新的
Chrome
)举办设计(即无需考虑包容性等)。

vue组件keep-alive

假若您做用一个巨型web的spa的时候,你有那一个router,对应的是众多少个页面。在页面的很快切换中,为了保障页面加载的频率,除了缓存机制之外,vue的keep-alive组件可以帮的上忙。

它会把组件保存在浏览器内存当中,方便你火速切换。

百度的lavas品类中就在vue-router当中使用keep-alive的零件,用它包裹着router-view。使用了keep-alive的组件内的多大校会保留,“是否要求重新联合数据”可以在vue-router的钩子中路由所带的参数执行判断。

多个进度(重点)

Electron
有二种进度:『主进程』和『渲染进度』。部分模块只可以在双边之一上运行,而有点则无界定。主进程越来越多地充当幕后角色,而渲染进程则是应用程序的顺序窗口。

注:可透过职务管理器(PC)/活动监视器(Mac)查看进度的相干消息。

Promise请求

es6的中间一个特色就是原生协理promise。在此间,我先不说异步编程里的generatoraync/await的性质。它们功效的落到实处都是依照promise。

Promise的特征在于:

此间更加讲一下,ES6在性能优化上得以行使promise或者async/await去减弱请求时间。在过去,很多jquery的页面在调用接口请求都是一个接口等另一个接口,串行执行所有请求,最终在做到最终的回调函数,如此类推。这样的写法会直接造成“回调地狱”。即使你用vue-resource,我也review到分外多的“回调地狱”的场合。为了从根本上解决这么些题目并加强费用功能,我指出优先使用promise。(async/await不急着投入使用),考虑到还有不少同事还在便捷地开发业务代码。

现在的vue-resource一度支撑promise的写法,为了更好地让技艺向后迈入,我提出将pagekit/vue-resource轮换称为mzabriskie/axioswebmodules/jsonpaxios是可以而且满足服务端和浏览器端,同构的写法有助于以后将技艺栈往SSR(服务端渲染)发展。jsonp本条库则是为着包容jsonp的哀求要求,要求对它举行了promise的包裹。

export function getJsonp(urlHost, key, data, _params) {
  return new Promise((resolve, reject) => {
    let url = urlHost + key;
    if (data) url += `?${querystring.stringify({ ...data, temp: new Date().getTime() })}`;
    const params = _params || { timeout: 15000 };
    if (!params.timeout) params.timeout = 15000;
    jsonp(url, params, (err, res) => {
      if (err) {
        reject(err);
      } else {
        resolve(res);
      }
    });
  });
}

Promise的应用需求防止以下的写法,

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

尽心尽力选用链式写法,

promise.then(function(value) {
  // step1
}).then(function(value){
  // step2
}).catch(function(value){
  // failure
})

互相的操作重即使Promise.all(),它可以将Promise操作的数组并行执行完毕然后在开展串行的操作。Promise.race()则是回到并行请求中伊始回到的央浼的越发结果。它们的使用可以有效地回落数量得到的大运。

主进程

主进度,平常是一个命名为 main.js 的公文,该公文是种种 Electron
应用的入口。它决定了拔取的生命周期(从打开到关门)。它既能调用原生元素,也能创造新的(两个)渲染进度。其它,Node
API 是置于其中的。

图片 2

壮大阅读

转发,请声明出处。总目录前段收集器

渲染进度

渲染进度是使用的一个浏览器窗口。与主进度不一样,它能存在多个(注:一个
Electron
应用只可以存在一个主进程)并且相互独立(它也能是隐藏的)。主窗口一般被取名为
index.html。它们就如超人的 HTML 文件,但 Electron 赋予了它们完整的
Node API。由此,那也是它与浏览器的分别。

图片 3

把它们想象成那样

Chrome(或其他浏览器)的种种标签页(tab)及其页面,就好比 Electron
中的一个单身渲染进度。即便关闭所有标签页,Chrome 依旧存在。那好比
Electron 的主进度,能打开新的窗口或关闭那一个动用。

注:在 Chrome
浏览器中,一个标签页(tab)中的页面(即除去浏览器本身部分,如搜索框、工具栏等)就是一个渲染进度。

图片 4

互动通讯

鉴于主进度和渲染进度各自负责差其余职责,而对于须要联合完结的任务,它们需求互相通讯。IPC就为此而生,它提供了经过间的报纸发表。但它只可以在主进度与渲染进程之间传递新闻(即渲染进度之间不可能展开直接通讯)。

图片 5

汇成一句话

Electron 应用似乎 Node 应用,它也凭借一个 package.json
文件。该文件定义了哪个文件作为主进度,并据此让 Electron
知道从何启动应用。然后主进度能制造渲染进度,并能使用 IPC
让双方间举行新闻传递。

图片 6

迄今,Electron
的根基部分介绍达成。该有的是依照作者以前翻译的一篇小说《Essential
Electron》
,译文可点击
这里


Vue 全家桶

该工具使用了 Vue、Vuex、Vuex-router。在工具基本定型阶段,由 1.x 升级到了
2.x。

为啥选用 Vue

对此作者来说:

Vue 1.x -> Vue 2.0 的版本迁移用
vue-migration-helper
即可分析出半数以上须要改变的地点。

网上已有成百上千有关 Vue 的科目,故在此不再赘言。至此,Vue 部分介绍落成。


js-xlsx

该库协理种种电子表格格式的辨析与转移。它由 JavaScript 完成,适用于前者和
Node。详情>>

脚下支撑读入的格式有(不断更新):

支撑写出的格式有:

现阶段该库提供的 sheet_to_json 方法能将读入的 Excel 数据转为 JSON
格式。而对于导出操作,大家需求为 js-xlsx 提供指定的 JSON 格式。

越来越多关于 Excel 在 JavaScript
中拍卖的学问可查看凹凸实验室的《Node读写Excel文件探究实践》。但该小说存在两处问题(均在
js-xlsx 实战的导出表格部分):

  1. 扭转头部时,Excel 的列新闻简单地因而 String.fromCharCode(65+j)
    生成。当列大于 26 时会出现问题。这么些题材会在后头章节中提交解决方案;
  2. 转换成 worksheet
    需求的组织处,出现逻辑性错误,并且会造成惨重的性能问题。逻辑问题在此不讲述,大家看看性能问题:
    随着 ECMAScript 的不断更新,JavaScript
    变得尤为有力和易用。固然如此,大家照旧要形成『物尽所用』,而不要『大材小用』,否则恐怕会得到“反效果”。那里导致性能问题的正是
    Object.assign()
    方法,该措施可以把自由多少个源对象的可枚举属性拷贝至目标对象,并赶回目标对象。由于该办法本身的兑现机制,会在此案例中发出大批量的冗余操作。在本案例中,单元格新闻是绝无仅有的,所以一贯通过
    forEach 为一个空对象赋值即可。提高 N
    倍性能的还要,也把逻辑性错误解决了。

原来的:

JavaScript

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

1
2
var result = 某数组.reduce((prev, next) =&gt; Object.assign({}, prev, {[next.position]: {v: next.v}}), {});
 

改为:

JavaScript

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

1
2
var result = 某数组.forEach((v, i) =&gt; data[v.position]= {v: v.v})
 

推行是检查真理的唯一标准

在知晓上述知识后,上边就谈谈在该项目举办中总计出来的技术、难点和要害

CSS、JavaScript 和 Electron 相关的学问和技能

高亮 table 的列

Excel 单元格选择 table 标签突显。在 Excel
中,被入选的单元格会高亮相应的『行』和『列』,以提示用户。在该行使中也有做相应的拍卖,横向高亮选择
tr:hover 完毕,而纵向呢?那里所使用的一个技巧是:

假设 HTML 结构如下:

JavaScript

div.container table tr td

1
2
3
4
5
div.container
  table
    tr
      td
 

CSS 代码如下:

JavaScript

.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 等 }

1
2
3
4
5
6
7
8
9
10
11
.container { overflow:hidden; }
td { position: relative; }
td:hover::after {
  position: absolute;
  left: 0;
  right: 0;
  top: -1个亿px; // 小目标达成,不过是负的&#x1f62d;
  bottom: -1个亿px;
  z-index: -1; // 避免遮住自身和同列 td 的内容、border 等
}
 

斜分割线

如图:图片 7

分割线可以通过 ::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 的列转换

JavaScript

// 将盛传的本来数转换为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 }

1
2
3
4
5
6
7
8
9
10
11
12
13
// 将传入的自然数转换为26进制表示。映射关系:[0-25] -&gt; [A-Z]。
function getCharCol(n) {
  let temCol = ”,
    s = ”,
    m = 0
  while (n &gt;= 0) {
    m = n % 26 + 1
    s = String.fromCharCode(m + 64) + s
    n = (n – m) / 26
  }
  return s
}
 

JavaScript

// 将盛传的26进制转换为自然数。映射关系:[A-Z] ->[0-25]。
function getNumCol(s) { if (!s) return 0 let n = 0 for (let i = s.length

1
2
3
4
5
6
7
8
9
10
11
12
// 将传入的26进制转换为自然数。映射关系:[A-Z] -&gt;[0-25]。
function getNumCol(s) {
  if (!s) return 0
  let n = 0
  for (let i = s.length – 1, j = 1; i &gt;= 0; i–, j *= 26) {
    let c = s[i].toUpperCase()
    if (c &lt; ‘A’ || c &gt; ‘Z’) return 0
    n += (c.charCodeAt() – 64) * j
  }
  return n – 1
}
 

为 DOM 的 File 对象扩张了 path 属性

Electron 为 File 对象额外增了 path
属性,该属性可收获文件在文件系统上的忠实路径。因而,你可以应用 Node
为非作歹。应用场景有:拖拽文件后,通过 Node 提供的 File API
读取文件等。

支撑周边的编写成效,如粘贴和复制

Electron 应用在 MacOS
中默许不支持『复制』『粘贴』等广泛编辑功效,由此需求为 MacOS
显式地安装复制粘贴等编制作用的菜单栏,并为此设置相应的快捷键。

JavaScript

// 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); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 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
应用也幸免不了『先开辟浏览器,再渲染页面』的手续。下边提供三种方式来减轻那种情状,以让程序更靠近原生应用。

  1. 指定 BrowserWindow 的背景颜色;
  2. 先隐藏窗口,直到页面加载后再呈现;
  3. 保留窗口的尺寸和地点,以让程序下次被打开时,如故保存的如出一辙大小和产出在一如既往的任务上。

对于第一点,若选拔的背景不是纯白(#fff)的,那么可指定窗口的背景颜色与其相同,以防止渲染后的剧变。

JavaScript

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

1
2
3
4
5
mainWindow = new BrowserWindow({
    title: ‘XCel’,
    backgroundColor: ‘#f5f5f5’,
};
 

对于第二点,由于 Electron
本质是一个浏览器,需求加载非网页部分的资源。因而,大家得以先隐藏窗口。

JavaScript

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

1
2
3
4
5
var mainWindow = new BrowserWindow({
    title: ‘ElectronApp’,
    show: false,
};
 

等到渲染进度初叶渲染页面的那一刻,在 ready-to-show
的回调函数中浮现窗口。

JavaScript

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

1
2
3
4
5
mainWindow.on(‘ready-to-show’, function() {
    mainWindow.show();
    mainWindow.focus();
});
 

对于第三点,小编并从未得以落成,原因如下:

  1. 用户一般是基于当时的情事对先后的尺寸和职位进行调整,即视情形而定。
  2. 如上是自己个人臆断,首假如自己懒。

其落到实处形式,可参考《4 must-know tips for building cross platform
Electron
apps》

咋样在渲染进程调用原生弹框?

在渲染进程中调用原本专属于主进度中的 API (如弹框)的方式有三种:

  1. IPC 通讯模块:先在主进程通过 ipcMain 举行监听,然后在渲染进度经过
    ipcRenderer 举行接触;
  2. remote 模块:该模块为渲染进度和主进度之间提供了便捷的简报方式。

对于第三种办法,在渲染进度中,运行以下代码即可:

JavaScript

const remote = require(‘electron’).remote remote.dialog.showMessageBox({
type: ‘question’, buttons: [‘不告诉你’, ‘没有梦想’], defaultId: 0,
title: ‘XCel’, message: ‘你的冀望是何许?’ }

1
2
3
4
5
6
7
8
9
10
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 的安装包却略显简洁(默许选项时)。

图片 8
Mac 常见的安装形式,将“左边的利用图标”拖拽到“左边的 Applications”即可

经过 electron-builder 生成的 Windows 安装包与咱们在 Windows
上常见的软件设置界面不太一致,它并未设置向导和点击“下一步”的按钮,只有一个设置时的
gif 动画(默许的 gif 动画如下图,当然你也可以指定特定的 gif
动画),由此也就关门了用户挑选安装路径等义务。

图片 9
Windows 安装时 默许突显的 gif
动画

比方你想为打包后的 Electron 应用(即经过
electron-packager/electron-builder
生成的,可平昔运行的次序目录)生成拥有点击“下一步”按钮和可让用户指定安装路径的常见安装包,可以品尝
NSIS 程序,具体可看这篇教程 《[教學]只要10分鐘學會使用 NSIS
包裝您的桌面軟體–安裝程式打包。完全免費。》

注:electron-builder
也提供了扭转安装包的配备项,切实查看>>

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
在首先渲染时,必要对种种子项进行开始化(如数据绑定等操作,以便拥有更快的创新速度),那对于数据量较大时,无疑会造成深重的性质问题。

即刻,我想开了三种缓解思路:

  1. Vue 是数码驱动视图的,对数码分段 push,即将一个宏大的天职务割为 N
    份。
  2. 友好拼接 HTML 字符串,再通过 innerHTML 几回性插入。

终极,我接纳了第二条,理由是:

  1. 性能最佳,因为每一遍执行多少过滤时,Vue 都要开展 diff,性能糟糕。
  2. 更契合当下采取的须要:纯显示且无需动画过渡等。
  3. 落到实处更简便

将本来繁重的 DOM 操作(Vue)转换为 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 问题。

JavaScript

const store = new Vuex.Store({ // … strict: process.env.NODE_ENV !==
‘production’ })

1
2
3
4
5
const store = new Vuex.Store({
  // …
  strict: process.env.NODE_ENV !== ‘production’
})
 

多进程!!!

前边说道,JavaScript
天生单线程,尽管再快,对于数据量较大时,也会现出拒绝响应的题材。因此必要Web Worker 或相近的方案去解决。

在那边我不选拔 Web worker 的原因有如下几点:

  1. 有此外更好的替代方案:一个主进程能创设八个渲染进程,通过 IPC
    即可进展多少交互;
  2. 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 种艺术展开报导:

  1. Storage
    API
    :对某个标签页的
    localStorage/sessionStorage 对象开展增删改时,其他标签页能透过
    window.storage 事件监听到。
  2. IndexedDB:IndexedDB
    是一个为了能够在客户端存储可观数额的结构化数据,并且在那一个数据上行使索引进行高性能检索的
    API。
  3. 由此主进度作为中转站:设主界面的渲染进度是 A,background process
    是 B,那么 A 先将 Excel 数据传递到主进程,然后主进度再转车到 B。B
    处理完后再原路再次回到,具体如下图。当然,也足以将数据存储在主进度中,然后在多少个渲染进度中选拔remote 模块来做客它。

该工具拔取了第三种格局的率先种状态:
图片 10

1、主页面渲染进度 A 的代码如下:

JavaScript

//① ipcRenderer.send(‘filter-start’, { filterTagList:
this.filterTagList, filterWay: this.filterWay, curActiveSheetName:
this.activeSheet.name }) // ⑥ 在某处接收 filter-response 事件
ipcRenderer.on(“filter-response”, (arg) => { // 拿四处理数据 })

1
2
3
4
5
6
7
8
9
10
11
12
//①
ipcRenderer.send(‘filter-start’, {
    filterTagList: this.filterTagList,
    filterWay: this.filterWay,
    curActiveSheetName: this.activeSheet.name
})
 
// ⑥ 在某处接收 filter-response 事件
ipcRenderer.on("filter-response", (arg) =&gt; {
    // 得到处理数据
})
 

2、作为中转站的主进程的代码如下:

JavaScript

//② 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) })

1
2
3
4
5
6
7
8
9
10
11
//②
ipcMain.on("filter-start", (event, arg) =&gt; {
    // webContents 用于渲染和控制 web page
    backgroundWindow.webContents.send("filter-start", arg)
})
 
// ⑤ 用于接收返回事件
ipcMain.on("filter-response", (event, arg) =&gt; {
    mainWindow.webContents.send("filter-response", arg)
})
 

3、处理繁重数据的 background process 渲染进度 B 的代码如下:

JavaScript

// ③ ipcRenderer.on(‘filter-start’, (event, arg) => { // 进行演算 …
// ④ 运算已毕后,再通过 IPC 原路再次来到。主进度和渲染进度 A
也要建立相应的监听事件 ipcRenderer.send(‘filter-response’, { filRow:
tempFilRow }) })

1
2
3
4
5
6
7
8
9
10
11
// ③
ipcRenderer.on(‘filter-start’, (event, arg) =&gt; {
    // 进行运算
    …
 
    // ④ 运算完毕后,再通过 IPC 原路返回。主进程和渲染进程 A 也要建立相应的监听事件
    ipcRenderer.send(‘filter-response’, {
        filRow: tempFilRow
    })
})
 

至今,我们将『读取文件』、『过滤数据』和『导出文件』三大耗时的数码操作均转移到了
background process 中处理。

此间,大家只开创了一个
background process,借使想要做得更可是,我们得以新建『CPU 线程数- 1 』
个的 background process
同时对数码进行处理,然后在主进度对处理后数据举办拼接,最后再将拼接后的数额再次来到到主页面的渲染进程。这样就可以充足榨干
CPU 了。当然,在此小编不会进展这些优化。

并非为了优化而优化,否则以珠弹雀。 —— 某网友

内存占有量过大

化解了履行功用和渲染问题后,发现也设有内存占用量过大的题材。当时猜疑是以下多少个原因:

  1. 三大耗时操作均放置在 background process
    处理。在简报传递数据的长河中,由于不是共享内存(因为 IPC 是按照Socket
    的),导致出现多份数据副本(在写那篇小说时才有了那相对合适的答案)。
  2. Vuex
    是以一个大局单例的情势开展田间管理,但它会是不是对数码做了一些封装,而导致性能的开销呢?
  3. 由于 JavaScript
    近年来不拥有积极回收资源的力量,所以只可以积极对闲置对象设置为
    null,然后等待 GC 回收。

鉴于 Chromium 选拔多进程架构,因而会涉嫌到进程间通信问题。Browser
进程在启动 Render 进度的长河中会建立一个以 UNIX Socket 为底蕴的 IPC
通道。有了 IPC 通道之后,接下去 Browser 进度与 Render
进度就以新闻的花样举办通信。大家将那种信息称为 IPC
新闻,以分别于线程消息循环中的音信。
——《Chromium的IPC信息发送、接收和散发机制分析》

概念:为了便于通晓,以下『Excel 数据』均指 Excel 的成套得力单元格转为
JSON 格式后的数码。

最简单处理的逼真是第三点,手动将不再须要的变量及时安装为
null,但效益并不明明。

后来,通过操作系统的『活动监视器』(Windows
上是职分管理器)对该工具的每阶段(打开时、导入文本时、筛选时和导出时)进行简短的内存分析,得到以下报告:

—————- S:报告分割线 —————-
经观望,首要耗内存的是页面渲染进程。上面通过截图阐明:
PID 15243 是主进度
PID 15246 是页面渲染进度
PID 15248 是 background 渲染进度

a、第一次开行程序时(第 4 行是主进度;第 1 行是页面渲染进度;第 3 行是
background 渲染进度 )

图片 11

b、导入文本(第 5 行是主进度;第 2 行是页面渲染进度;第 4 行是
background 渲染进度 )
图片 12

c、筛选数据(第 4 行是主进度;第 1 行是页面渲染进度;第 3 行是
background 渲染进程 )
图片 13

鉴于 JavaScript 方今不享有积极回收资源的效应,所以不得不积极将目的设置为
null,然后等待 GC 回收。

据此,经过一段时间等待后,内存占用如下:
d、一段时间后(第 4 行是主进程;第 1 行是页面渲染进度;第 3 行是
background 渲染进度 )
图片 14

由上述可得,页面渲染进度由于页面元素和 Vue 等 UI
相关资源是稳定的,占用内存较大且无法回收。主进度占用资源也不可能获取很好释放,暂时不了然原因,而
background 渲染进度则较好地放出资源。

—————- E:报告分割线 —————-

依据报告,初叶得出的定论是 Vue 和通讯时占用资源较大。

基于该工具的其实使用场景:Excel
数据只在『导入』和『过滤后』七个阶段必要显示,而且突显的是经过
JavaScript 拼接的 HTML 字符串所构成的 DOM 而已。因而将表格数据放置在
Vuex 中,有点滥用资源的猜疑。

另外,在 background process 中也有存有一份 Excel
数据副本。由此,索性只在 background process 存储一份 Excel
数据,然后每当数据变动时,通过 IPC 让 background process 重返拼接好的
HTML
字符串即可。那样一来,内存占有量立刻下降许多。其它,那也是一个一举多得的优化:

  1. 字符串拼接操作也转移到了
    background process,页面渲染进度进一步缩减耗时的操作;
  2. 内存占有量大大减小,响应速度也获取了进步。

事实上,这也有点像 Vuex 的『全局单例格局管理』,一份数据就好。

理所当然,对于 Excel 的中坚信息,如行列数、SheetName、标题组等均如故保留在
Vuex。

优化后的内存占有量如下图。与上述报告的第三张图比较(同一等级),内存占有量下落了
44.419%: 图片 15
其余,对于不须求响应的数码,可透过 Object.freeze()
冻结起来。那也是一种优化手段。但该工具方今并没有利用到。

迄今,优化部分也演讲完毕了!


该工具如今是开源的,欢迎我们使用或引进给用研组等有亟待的人。

你们的汇报(可提交 issues /
pull
request
)能让那个工具在动用和意义上不断完善。

最后,感谢 LV
在产品设计、界面设计和优化上的武力支撑。全文完!

打赏扶助自己写出越来越多好作品,谢谢!


打赏小编

打赏支持我写出更多好小说,谢谢!

任选一种支付办法

图片 16
图片 17

1 赞 2 收藏
评论

有关小编:刘健超-J.c

图片 18

前端,在路上…http://jchehe.github.io
个人主页
·
我的篇章
·
19
·
    

图片 19

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图