注意:附加在原始问题末尾的附加信息,如编辑#1__,详细说明后端的request-promise是如何导致UI冻结的。请记住,一个纯CSS动画暂时挂起,您可能只需跳过编辑(或阅读所有的完整性)。
安装程序
我正在使用电子开发一个桌面网络应用程序。
有一次,用户需要输入并提交一些数据。当他们单击"submit“时,我使用JS显示此css加载动画 (右下角加载器),并将数据异步发送到后端.
- 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()是一个异步方法,没有其他设置的选项。
问题
通常,0ms延迟足以允许在阻塞事件发生之前更改DOM。但不是在这里。无论是否使用setTimeout(),仍然存在延迟。
所以,再加点时间.
loader.classList.remove('_hide');
setTimeout(function() {
ipcRenderer.send('credentials:submit', credentials);
}, 100);太棒了!装载机在提交时立即显示!但是..。在100毫秒后,动画停止在它的轨道上,大约500毫秒左右,然后回到学习。
这种不工作的->不工作->工作模式,不管延迟长度如何。一旦ipcRenderer开始做一些事情,一切就会停止。
所以..。为什么!?
这是我第一次看到这种行为。我对HTML/CSS/JS相当熟悉,但我承认我对NodeJS和电子很陌生。为什么我的纯CSS动画会被ipcRenderer停止,我能做些什么来补救这个问题呢?
编辑#1 -附加信息
在后端(NodeJS)中,我使用请求-承诺调用外部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...
});
}buggy冻结行为只发生在第一个API调用上。连续的API调用(即在不重新启动NodeJS后端的情况下刷新桌面应用程序),不要导致挂起。即使我调用了不同的API方法,也没有任何问题。
现在,我已经实现了以下恶意解决方案:
首先,用BrowserWindow初始化第一个show:false.
window = new BrowserWindow({
show: false
});当窗口准备好后,发送一个ping到外部API,并且只在成功响应后显示该窗口.
window.on('ready-to-show', function() {
apiWrapper.ping(function(response) {
if(response.error) {
app.quit();
}else {
window.show(true);
}
});
});这一额外步骤意味着窗口出现前大约有500 is的延迟,但是所有连续的API调用(无论是.ping()还是其他调用)都不再阻止UI。我们快到回调地狱的边缘了,但这还不算太糟。
所以..。这是一个request-promise问题(据我所知,这是异步的)。不知道为什么这种行为只出现在first call上,所以如果您知道,请随时通知我!否则,这个讨厌的小东西现在就得做了。
(注意:我是唯一一个使用这个桌面应用程序的人,所以我不太担心显示"ping失败“消息。对于商业版本,我会提醒用户API调用失败。)
发布于 2018-01-24 23:01:46
值得检查请求-承诺内部设置如何加载模块。读取它时,似乎在调用请求时存在某种延迟加载(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 require解析是同步的)。
我不能说这是具体的原因,但值得一查。正如注释中所建议的,尝试其他库或裸内部模块(如电子的net)来排除。
https://stackoverflow.com/questions/48430578
复制相似问题