繁体   English   中英

NodeJS和Electron - 后端的请求承诺冻结了前端的CSS动画

[英]NodeJS and Electron - request-promise in back-end freezes CSS animation in front-end

注意:附加信息作为编辑#1附加到原始问题的末尾,详细说明了后端中的request-promise如何导致UI冻结。 请记住,纯CSS动画暂时挂起,你可能只是跳到编辑(或完全阅读全部)

设置

我正在使用Electron开发桌面webapp。

有一次,用户需要输入并提交一些数据。 当他们点击“提交”时,我使用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);

大! 装载机在提交后立即显示! 但是...在100ms之后,动画在其轨道上停止了大约500ms左右,然后又回到了chooching。

无论延迟长度如何,这种工作 - >不工作 - >工作模式都会发生。 一旦ipcRenderer开始做东西,一切都会停止。

所以为什么!?

这是我第一次看到这种行为。 我非常精通HTML / CSS / JS,但我不熟悉NodeJS和Electron。 为什么我的纯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);
        }
    });
});

这个额外的步骤意味着在窗口出现之前有大约500ms的延迟,但随后所有连续的API调用(无论是.ping()还是其他)都不再阻止UI。 我们正处于回调地狱的边缘,但这并不算太糟糕。

所以...这是一个request-promise问题(根据我从文档中可以看出,这是异步的)。 不确定为什么这种行为只会在第一次通话时出现 ,所以如果您知道,请随时告诉我! 否则,这个小小的hacky就必须要做了。

(注意:我是唯一一个会使用这个桌面应用程序的人,因此我不太担心显示“ping失败”消息。对于商业版本,我会提醒用户API调用失败。)

值得检查请求承诺如何在内部设置模块加载。 阅读它,似乎在调用请求时有一种延迟加载( 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上运行裸节点.js)如果模块加载是第一次调用的主要成本,那么它将阻止主进程直到模块加载(导致node.js require解析是同步的) )

我不能说这是具体原因,但值得检查。 正如评论中所建议的那样,尝试使用其他lib或裸内部模块(如Electron的net )来排除。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM