给一家企业做项目。总不能跑过去进行升级。有没有在线升级方案.
node.js pm2 部署在公司内网,服务器能上外网,但不能被访问,请问用什么方案对node.js 写的业务进行升级。
有人用过sails框架吗 为什么我在做路由的时候,入库操作总显示user.create()不是一个方法
用Amazon EC2的进来说说,有没有碰到控制台界面卡住的情况
第一次进入Console以后,会卡住几分钟,然后才显示界面。(但科学上网后,就没有这种现象。)
天猫前端等着你
如果你有听过WEEX,也许你对VUE玩得很溜,也许你对React如何构建敲大型中台有点兴趣。
Let’s Play, Let’ Crazy
Sure,这就是你的土壤
- 我们玩尽各种主流技术,一群放荡不羁的极客,总有你爱玩的
- 极致,是我们的追求,moblie or native,we just do it the best. 狂热的性能控,为的是提供千万及亿用户丝般顺滑的体验
- 潮流,从来不缺,AR、VR、3D场景,统统不漏
- 一年一度双十一、618,逛吃逛吃之外,还有千万级用户等你来浪
- 理想生活上天猫~!
玩累了?各种福利hi到爆
猫厂啥都不缺,就是福利不要太多。老套路午后水果,五险一金就忽略不提了。来点有意思的?
- 巨额年终奖 + 13薪不会漏掉你的份,没错,我们的年终奖不是13薪
- 单身的你,是否想到水嫩水嫩西湖妹子
- ™原生态一大波水萌水萌,各种内外介绍帖不要太多,每天翻10篇,天天不重样,看妹子看到手软(喂…)
- 各种极客大咖分享,一个月看几次总是不过分
- 什么,你说不想只写一辈子代码?来呀,快活吧!原生态课程,各种业务大咖给你上夜校,For free!
嘘…有些事情,我们偷偷说,老板知道了要GG
- 各种潜福利,买房租房,各种补贴钜惠…闷声发大福
- 来呀,就给你买好全套…black man??保险(真·全套保险),看病买药,根本不花自己钱
- 园区配套校医啦、健身房、壁球场、按♂摩♀房,你要玩的,我们从来不会漏
- 还有&*fs.)^&#.
阿,老板你回来啦,嗯…<br/><br/><br/><br/><br/>
咳咳…来点正题
你的团队很精彩,各种方向各种搞
天猫事业部-产品技术部-交易链路&行业开发-前端,招聘资深前端工程师和前端技术专家。 团队在业务上对应天猫主要行业(如天猫超市、天猫国际、电器城、阿里汽车、天猫家装等等)及天猫核心的交易系统。 横向上同时会参与主导阿里、天猫前端的多项横向技术体系。 团队专注于以工程化手段提升开发效率,以数据智能化的驱动业务进步,构建高性能的用户交互解决方案。
你的工作很炫酷,怎么玩由你来
- 业务工作上:
- 消费者端业务:支撑天猫电器城、手机、猫宁等业务,负责PC/Mobile相关频道产品和导购营销工具的开发,不断提高消费者购物体验。
- 供应链相关业务:支撑阿里电商体系由营销导购平台向智能化供应链平台的升级,提升阿里电商商品品质,提升商业运行效率。
- 技术工作上:
- 效率提升:在理解前端开发流程的基础上,结合前端实际建立或优化提升工作效率的工具;
- 方案定制:在理解产品业务的基础上,提升产品的用户体验和业务价值,技术驱动业务的发展;
- 体验优化:对具体的产品进行性能优化,实现极致的页面加载、执行和渲染时间;
- 团队协作:关注前端前沿技术研究,通过新技术服务团队和业务。
- 技术细节上:
- 团队目前前端框架使用 React、Vue2.0,使用ES6、7进行具体开发工作。
- 面向企业中后台业务,自主研发组件化DSL方案Relim,将页面开发难度降低到只写模板。
- 在Web和Native融合、Web To Native方面,参与Weex的建设,并使用Weex进行消费者端业务开发。
- Node方面,自主研发前端工程体系相关工具,并有大量业务使用Node做服务端开发。
展示你的极客一面吧
- 熟练使用各种前端技术,包括HTML/CSS/JavaScript/等。
- 具备跨终端的前端开发能力,在Web(PC+Mobile)/Node.js/Native App三个方向上至少精通一个方向,具备多个的更佳,鼓励在Native和Web技术融合上的探索。
- 对前端工程化与模块化开发有一定了解,并有实践经验(如RequireJS/SeaJS/KISSY等)。
- 至少熟悉一门非前端的语言(如Java/PHP/C/C++/Python/Ruby),并有实践经验。
- 具备优秀的团队协作精神,能利用自身技术能力提升团队整体研发效率,提高团队影响力。
- 对前端技术有持续的热情,个性乐观开朗,逻辑性强,善于和各种背景的人合作。
请邮箱疯狂骚扰:jogis.zjj@alibaba-inc.com
一个桌面应用版的flappyBrid
*** 今天分享一个用javascript和electron结合起来的flappyBrid** demo是需要node和npm和electron、electron-packager 安装electron建议大家切换npm镜像
在.npmrc中进行添加
registry=https://registry.npm.taobao.org
ELECTRON_MIRROR=http://npm.taobao.org/mirrors/electron/
1.下载源代码
https://github.com/wodb/electron-electron-packager-demo
2.运行
npm start
3.打包成可执行文件
npm run packager
console.log(''仅配置了Windows64位)
nodejs关于图片加解密
各位仁兄,nodejs有没有什么加密图片的方案?
Vue-router钩子在路径变化时无法生效。
有一些组件想根据路径变化进行选择展示。但路由的钩子无法生效。 我测试了API的两个钩子。
beforeRouteEnter(to, from, next) {
next(vm => {
vm.init()
})
},
beforeRouteUpdate(to, from, next) {
next(vm => {
vm.init()
})
},
判断函数写在了init函数中。
init() {
//接受ablumItem选择显示页面
var params = this.$route.params;
this.show[params.ablumItem] = true;
},
为什么钩子函数只在第一次进入组件时生效。
webpack 构建的项目,运行出错,求指导
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! new_pake@1.0.0 dev: node build/dev-server.js
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the new_pake@1.0.0 dev script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in: npm ERR! C:\Users\lele\AppData\Roaming\npm-cache_logs\2017-06-24T12_29_00_580Z-debug.log
请问 pm2 启动的node 服务 和docker启动的服务有什么不同吗
请问 pm2 启动的node 服务 和docker启动的服务有什么不同吗 fe机器只会运行fe的服务。 后段服务只会运行后段服务。 只有一个应用,docker隔离应用。vm隔离用户。 求助。。。。
不知道nodejs 怎么让这样的循环逻辑和同步代码一样呢
半夜问一个路径的问题,懵了
首先,上图是我的包结构,
然后,在 admin 中有路由到 index.html , 然后在 html 中相对路径是这个,
结果,chrome调试竟然一直都是404,NOT FOUND,
why? 好久没上来水贴,没通宵撸了,求大牛
关于debug
新建的express项目,版本4.15.0。在webstorm里运行,日志输出
“D:\Program Files (x86)\JetBrains\WebStorm 2016.1\bin\runnerw.exe” “C:\Program Files\nodejs\node.exe” --debug-brk=54994 www Debugger listening on port 54994
debug('Listening on ’ + bind); 没找到输出到哪儿了。谁能帮忙解释一下么
使用webstorm上传代码到github总是出错
这是上传项目出错 Successfully created project ‘nodejs’ on GitHub, but initial push failed: unable to access ‘https://github.com/15826954460/nodejs.git/’: Failed to connect to 192.168.1.1 port 80 度娘谷歌了各种方法,都试过,还是不知其所以然,依然会有这样的问题
$ ssh-key -t rsa -C "个人邮箱" bash: ssh-key: command not found
柏松@DESKTOP-C0KFRIV MINGW64 ~/Desktop (master) $ ssh-keygen -t rsa -C "个人邮箱" Generating public/private rsa key pair. Enter file in which to save the key (/c/Users/柏松/.ssh/id_rsa): /c/Users/柏松/.ssh/id_rsa already exists. Overwrite (y/n)?
$ ssh-keygen -t rsa -C "个人邮箱" Generating public/private rsa key pair. Enter file in which to save the key (/c/Users/柏松/.ssh/id_rsa):
Overwrite (y/n)? y Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /c/Users/柏松/.ssh/id_rsa. Your public key has been saved in /c/Users/柏松/.ssh/id_rsa.pub. The key fingerprint is: SHA256:4NdTSYR4a3vBIeJJElRQTSVPdnJEN6wPRCPSrC/YhLc 624793604@qq.com The key’s randomart image is: ±–[RSA 2048]----+ | .+=o===O=*…| | . + Oo.o.| | .+.+.+=… | | . oo=o.oo | | . S.=. .o | | o E.o. . | | … | | | | | ±—[SHA256]-----+ ssh -T git@github.com Warning: Permanently added the RSA host key for IP address ‘192.30.255.112’ to t he list of known hosts. Hi 15826954460! You’ve successfully authenticated, but GitHub does not provide s hell access.
以上为通过git和电脑生成ssh,经检查也是成功的,现在不管是提交还是clone都会报 错 unable to access ‘https://github.com/15826954460/nodejs.git/’: Failed to connect to 192.168.1.1 port 80 不知道是各位是否可以给点意见,帮忙解决一下,三天之前还是一切ok, 感激不尽啊!不知道是不是端口号的问题,也不知道如何去配置github和本机的端口号进行配置
XCel 项目总结 - Electron 与 Vue 的性能优化
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 结合了 Chromium、Node.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在产品规划、界面设计和优化上的强力支持。全文完!
node.js 的mysql模块读取时间 怎么是这样的,怎么解决?
读取输出后: 很明显和我数据库中的格式不一样啊!
Easy-Monitor 2.0: 开启你的 Node.js 内核性能监控
I. 写在最前面
Easy-Monitor 1.x 的版本在今年三月的时候发布了,陆续从最初的仅仅为了做一个短时间 ( 5s ) 的 cpu-profiling 查看函数瓶颈,到后面加入了针对疑似内存泄漏点的排查功能。
整个 1.x 版本主要还是试验一下自己的做内核监控的可行性和想法,所以在使用上和设计架构上没有做太多的考量,导致易用性和兼容性上存在一些问题,因此从 5 月中旬开始到现在,对这个项目做了一个彻底的重构,也是现在这个 2.0 版本的初衷~
II. 功能
- 服务器状态概览信息展示
- 实时 CPU 函数性能分析,帮助定位程序的性能瓶颈点
- 实时 Memory 堆内内存结构分析,帮助定位到内存疑似泄漏点
2.0 的一些新特性
- 基于 vue.js 和 iview 组件全新设计的 UI
- 全面兼容 v4.x ~ v8.x
- 新增概览 Overview 展示页
- 支持 动态更新配置,无需重启一键生效
- 支持 Stream 流式解析更大的 HeapSnapshot
- 支持 Cluster 集群部署,支持定制 私有协议
III. 快速开始
- 安装模块
执行如下命令安装 Easy-Monitor:
npm install easy-monitor
- 项目中引入
在你的项目入口文件中按照如下方式引入,当然请传入你的项目名称:
'use strict';
const easyMonitor = require('easy-monitor');
easyMonitor('你的项目名称');
好了,此时你所需要做的一切都已就绪,接下来以你喜欢的方式运行项目即可,不管是 nohup
还是 pm2
,亦或是直接 node
启动均可。
- 访问监控页面
打开你的浏览器,访问 http://localhost:12333,即可看到进程界面。
- 完整样例 & Demo
为了帮助大家更好的理解使用,下面编写一个 Easy-Monitor 嵌入 Express 应用的完整例子
'use strict';
const easyMonitor = require('easy-monitor');
easyMonitor('Mercury');
const express = require('express');
const app = express();
app.get('/hello', function (req, res, next) {
res.send('hello');
});
app.listen(8082);
将上述的内容保存成一个 js 文件,启动后访问 http://127.0.0.1:12333即进入 Easy-Monitor 的首页,就是这样的简单!
这里有一个在线真实的 Demo 地址:Easy-Monitor Demo,可以点击进入自行尝试一番。
更多关于 集群部署、深度定制化开发、通用配置以及动态更新配置的说明可以查看 Easy-Monitor 详细文档。
IV. 设计架构
这个项目旨在帮助大家更加深入地理解自己的 Node 项目运行时状态,以便能够在想做性能优化时更有针对性,也考虑到使用的难易程度,所以对于 快速部署和 集群 C/S 模式部署两种都做了支持,整体设计架构如下:
快速部署
快速部署模式下,web 页面展示的进程会以 fork 的形式自动启动,采集内核数据的客户端则会绑定到业务进程,两者间采用默认的 tcp 通信模式:
如上图所示,这种部署模式下,优点是仅需要 require 即可,无任何额外操作,开箱即用。缺点也比较明显,如果项目是分布在不同的服务器上,则需要每次都输入对应的项目所在服务器地址才能访问。
集群 C/S 部署
这种部署模式其实就是独立部署 dashboard 进程,采集内核数据的客户端则分散到各个业务进程,数据统一上报给独立部署的 dashboard 进程,整体设计架构如下:
这种部署模式下,在业务项目本身集群化部署的情况下非常易于统一查看,省去了快速部署模式下每次访问不同地址的烦恼。
V. 图文使用说明
动态更新配置
进入监控 web 页面首页后,点击项目标题,即可打开动态更新配置的 Modal 框 (需要版本 >= v2.1.0),如图:
弹出框具体每一项的内容和含义详见 开启动态更新配置。
OS 信息概览
进入监控 web 页面首页后,找到对应的项目,所在服务器选择你想查看的服务器,进程一项选择你想查看的进程,解析类型一项选择 OS,最后点击项目标题旁边的 start按钮,如下图所示:
即可进入当前选中进程的概览信息页面,此页面可以看到服务器的 CPU 使用率,以及选中的进程的 Memory 占用情况,其中内存占用展示了三类:
- heapUsed: 正在使用的堆内内存大小
- heapTotal: 申请的总堆内内存大小
- rss: 堆外分配的内存大小
如下图所示:
这个 line-charts 展示模块的设计实现参考了 @JerryC8080 的 Memeye项目,本文末和源码中做了特别标注。
CPU 数据采集分析函数运算瓶颈
使用方法
进入监控 web 页面首页后,找到对应的项目,所在服务器选择你想查看的服务器,进程一项选择你想查看的进程,解析类型一项选择 CPU,最后点击项目标题旁边的 start按钮,如下图所示:
如果你没有更改过启动参数,那么会进行 5s(默认值) 的 CPU-Profiling,然后进行分析,展示结果包含:
- 执行耗费时间大于 500ms(默认值) 的函数列表
- 执行耗费时间最长的 5个(默认值) 函数
- V8 引擎逆优化最频繁的 5个(默认值) 函数
如图所示:
这里可以看到,我们将鼠标移至 系统路径一栏后,会在气泡框内展示出对应函数的完整的在服务器上的路径。下面解释下图表中的元素含义:
函数运算耗费时长相关
- 函数名称:即为编写的 js 函数名称
- 执行时长:该函数的运算时长,注意如果函数内包含异步操作,那么异步操作花费的时间是不统计在内的。这个时长就是指纯函数本身占据CPU运算的时间,所以可以定位到 CPU 运算瓶颈点。
- 占据调用者百分比:这里指的是本函数执行的时长占据调用者函数的总执行时长的百分比
- 系统路径:函数在服务器的具体文件路径
引擎逆优化相关
- 函数名称:即为编写的 js 函数名称
- 逆优化原因:此函数被 V8 引擎逆优化的原因
- 系统路径:函数在服务器的具体文件路径
动态更改 CPU 配置,获得更多数据
上面使用方法一节中看到很多数值被标注为 默认值,这表示这些值我们可以通过动态修改 CPU-Profiling 的配置来进行调整,这是一个动态调整的例子:
想对部署的项目进行压测 10 分钟,期间采集 CPU 数据,过滤出执行耗费大于 100ms 的函数,并且分析的结果每一项展示 50 条。
那么可以按照上面提到的方法进入动态更新配置的 Modal 框,修改参数如下图所示:
修改完毕后,点击 Modal 弹出框右下角的 确定按钮,即可通知服务器更改配置,保存成功后再按照上面的使用方法进行 CPU 数据采集和分析,等待约 10 分钟就可以看到结果。
关于CPU 动态配置中的自定义过滤
在上面的截图中可以看到,CPU 动态配置项中还有个按钮是 自定义过滤,这个是用来对 CPU 采集数据分析结过做过滤用的。
项目默认会过滤掉路径中包含 node_modules
、anonymous
等系统函数,这样可以保证结果中只包含开发者编写的函数,那么关闭自定义过滤的话会将系统函数也展示在内。
自定义过滤函数大家也可以根据项目需求而自行注入,具体可以看开发文档中的介绍: 自定义过滤。
Memory 数据采集分析定位疑似内存泄漏点
使用方法
进入监控 web 页面首页后,找到对应的项目,所在服务器选择你想查看的服务器,进程一项选择你想查看的进程,解析类型一项选择 MEM,最后点击项目标题旁边的 start按钮,如下图所示:
页面会对堆内内存分析中间过程进行一些展示,提高体验,等分析完毕后,即会展示出对应的结果,如下图所示:
这里根据分析当前进程堆内分配内存的结构,计算得出 RetainedSize 最大的节点占据总的堆内分配内存占比来判断是否有内存泄漏风险,以及对应的疑似泄漏节点引力图。
这一部分引力图详细定位内存泄漏点的逻辑和 Easy-Monitor 1.x 没有变化,可以参见上一篇文章来获取详情: 轻松排查线上Node内存泄漏问题
动态更改 Memory 配置,获得更多数据
Memory 分析同样也提供了一些可以动态更改的配置,试看如下场景:
Node 项目发生内存泄漏时,想获取更多的疑似内存泄漏点,以及需要更多的子节点信息和引力图深度来排查定位内存泄漏点,那么我们可以通过修改提供的动态配置来达到不重启服务器即可生效的目的,如下图所示:
这里将默认的展示 5 个疑似内存泄漏点更改为 10 个,将引力图的每一个节点的展开子节点数从默认的 5 个更改为 8 个,将引力图深度从默认的 25 更改为 50,这样就能获取到更多的内存信息。
关于 Memory 动态配置中的 Root 节点配置
Root 节点信息的展示是帮助大家更深入地理解当前的堆内内存结构,对于排查内存泄漏并没有太大帮助,但是这一项打开后会增加浏览器下载的 HeapSnapshot 分析结果数据大小,可以将其关闭掉。
VI. 特别感谢
重构过程中思路参考了一些开源项目,在最后特别感谢下 @JerryC8080:
- Memeye:作者为 JerryC8080,2.0 版本的 overview 页面实现和 logger 模块实现参考了 Memeye项目
源代码中对应位置也做了标注,感谢作者们的开源精神。
VII. 结语
Easy-Monitor 项目我个人会长期维护下去,下一阶段的计划大致如下:
- 研究下 Node 8 提供的 N-API,以将计算量巨大的 CPU 和 HeapsnapSnapshot 运算解析部分移植成扩展,放入单独的计算线程中来进一步提升性能。
- 研究下 Chrome 最新提供的 Record Allocation Profiler 和 Record Allocation Timeline 的实现,看看能不能合并入 Easy-Monitor 的 Memory 分析部分实现线上 Node 项目的实时分析。
最后本项目地址在 Easy-Monitor,如果使用中遇到问题可以提 issue,保证快速响应。
如果本项目对您有用欢迎 star,如果想一起开发或者有更多想法也欢迎联系我~
EJS如何在循环中显示序号问题
如题。。。 这样写报错,应该怎样写? 有知道的请告知一下
redux的一些笔记
位于github:redux 的一些笔记
各位大神log4js的console 改为 stdout是什么意思?
rt,console跟stdout有什么区别? 在V1.0以下怎么修改? 多谢了~
类似于百度网盘的点击右键上传文件的问题
一个桌面应用程序:(类似于百度网盘),选中文件,点击“上传到网盘”:
, 右键文件一次,就传过来一次所点击文件所在的路径,在main.js文件中,保存在process.argv里 问题是:如何监听点击上传的文件一次(也就是process.argv的路径改变一次)然后自动根据process.argv中的路径自动执行上传文件的函数呢?