NodeJS 和 Electron - 后端的请求承诺冻结前端的 CSS 动画
Posted
技术标签:
【中文标题】NodeJS 和 Electron - 后端的请求承诺冻结前端的 CSS 动画【英文标题】:NodeJS and Electron - request-promise in back-end freezes CSS animation in front-end 【发布时间】:2018-07-03 23:25:56 【问题描述】:注意:附加到原始问题末尾的附加信息为 Edit #1,详细说明后端中的 request-promise
如何导致 UI 冻结。请记住,纯 CSS 动画会暂时挂起,您可能可以直接跳到编辑处(或完整阅读全部内容)
设置
我正在使用Electron 开发桌面网络应用程序。
在某一时刻,用户需要输入和提交一些数据。当他们点击“提交”时,我使用JS显示this css loading animation(右下加载器),并将数据异步发送到后端......
- html -
<button id="submitBtn" type="submit" disabled="true">Go!</button>
<div class="submit-loader">
<div class="loader _hide"></div>
</div>
- JS-
form.addEventListener('submit', function(e)
e.preventDefault();
loader.classList.remove('_hide');
setTimeout(function()
ipcRenderer.send('credentials:submit', credentials);
, 0)
);
._hide
只是
._hide
visibility: hidden;
其中ipcRenderer.send()
是async method,没有其他设置选项。
问题
通常,0ms
延迟足以允许在阻塞事件发生之前更改 DOM。但不是在这里。不管是否使用setTimeout()
,还是有延迟的。
所以,添加一点延迟...
loader.classList.remove('_hide');
setTimeout(function()
ipcRenderer.send('credentials:submit', credentials);
, 100);
太棒了!加载程序在提交后立即显示!但是... 100 毫秒后,动画停止在其轨道上,大约 500 毫秒左右,然后重新开始选择。
无论延迟长度如何,这种工作 -> 不工作 -> 工作模式都会发生。只要ipcRenderer
开始做事,一切都会停止。
那么...为什么!?
这是我第一次看到这种行为。我非常精通 HTML/CSS/JS,但对 NodeJS 和 Electron 来说我是公认的新手。为什么我的 pure CSS 动画被 ipcRenderer
停止,我该怎么做才能解决这个问题?
编辑 #1 - 附加信息
在后端 (NodeJS) 中,我使用 request-promise 调用外部 API。当后端收到ipcRenderer
消息时会发生这种情况。
var rp = require('request-promise');
ipcMain.on('credentials:submit', function(e, credentials)
var options =
headers :
... api-key...
,
json: true,
url : url,
method : 'GET'
;
return rp(options).then(function(data)
... send response to callback...
).catch(function(err)
... send error to callback...
);
错误的冻结行为仅在第一次 API 调用时发生。连续的 API 调用(即在不重新启动 NodeJS 后端的情况下刷新桌面应用程序),不会导致挂起。即使我调用不同的 API 方法,也没有问题。
目前,我已经实现了以下 hacky 解决方法:
首先,用show:false
初始化第一个BrowserWindow
...
window = new BrowserWindow(
show: false
);
当窗口准备好后,向外部 API 发送 ping,只有响应成功后才显示窗口...
window.on('ready-to-show', function()
apiWrapper.ping(function(response)
if(response.error)
app.quit();
else
window.show(true);
);
);
这个额外的步骤意味着在窗口出现之前有大约 500 毫秒的延迟,但随后所有连续的 API 调用(无论是.ping()
还是其他)都不再阻塞 UI。我们正接近callback hell,但这还不错。
所以...这是一个request-promise
问题(据我从文档中得知,这是异步)。不知道为什么这种行为只出现在第一次调用,所以如果你知道,请随时告诉我!否则,现在就不得不做一些小技巧了。
(注意:我是唯一会使用此桌面应用程序的人,所以我不太担心会显示“ping 失败”消息。对于商业版本,我会提醒用户注意API 调用失败。)
【问题讨论】:
我遇到了类似的问题。这在我的情况下修复了它github.com/electron/electron/issues/1854#issuecomment-167606793 @Vector 我不确定我是否看到了它。众所周知,代码正是我处理它的方式(使用ipcRenderer
和ipcMain
)。我已经对原始问题添加了一个编辑,因为似乎问题出在request-proimise
你可以试试axios等其他模块
【参考方案1】:
值得检查 request-promise 如何在内部设置模块加载。阅读它,似乎在调用请求时有一种延迟加载(https://github.com/request/request-promise/blob/master/lib/rp.js#L10-L12)。快速试用
const convertHrtime = require('convert-hrtime');
const a = require('request-promise');
const start = process.hrtime();
a(uri: 'https://requestb.in/17on4me1');
const end = process.hrtime(start);
console.log(convertHrtime(end));
const start2 = process.hrtime();
a(uri: 'https://requestb.in/17on4me1');
const end2 = process.hrtime(start2);
console.log(convertHrtime(end2));
返回值如下:
seconds: 0.00421092,
milliseconds: 4.21092,
nanoseconds: 4210920
seconds: 0.000511664,
milliseconds: 0.511664,
nanoseconds: 511664
第一次通话显然比后续通话花费的时间更长。 (当然数量可能会有所不同,我在相对较快的 cpu 上运行裸 node.js)如果模块加载是第一次调用的主要成本,那么它将阻塞主进程直到模块被加载(导致 node.js require
resolve是同步的)
我不能说这是具体原因,但值得检查。正如评论中所建议的,尝试其他 lib 或裸内部模块(如 Electron 的 net
)来排除。
【讨论】:
感谢您花时间梳理代码并进行测试。如果没有任何配置选项,我认为我的 hacky 解决方法将是我最好的选择。我会查看其他库,但是将我拥有的所有 API 包装器转换为它并不是一个微不足道的时间。下一次,在我走得太远之前,我肯定会做一些单元测试。以上是关于NodeJS 和 Electron - 后端的请求承诺冻结前端的 CSS 动画的主要内容,如果未能解决你的问题,请参考以下文章
处理从 React 应用程序到 NodeJS 后端的长时间运行的发布请求时的建议
[electron 工具] 使用 electronvue 和 nodejs 做一个 SOAP 测试工具之一 ( 简介 )
nodejs/electron-forge/node-gyp:在尝试了我可以在网上找到的所有提示后,找不到任何要使用的 Visual Studio 安装