节点.on方法触发太多次

时间:2018-08-31 08:09:21

标签: javascript node.js electron

我有一个Electron应用程序,向用户显示目录列表。当用户单击按钮时,我的界面脚本interface.js将清除容器div并将消息发送到main.js。收到消息后,main.js会将目录扫描到文件名数组中,并将该数组作为响应返回给interface.js。 Interface.js使用.on方法,该方法会在收到响应时触发并使用数组的内容更新容器div。

这是我第一次真正尝试使用Node,就界面行为而言,一切工作都很出色!太好了,只有几个小时,我已经爱上了Node!

但是,在调试/压力测试时,我在.on方法中将返回的数组打印到控制台,并注意到一些奇怪的行为。用户第一次单击该按钮时,.on方法将运行一次(通过向控制台发送的一条消息进行验证)。用户第二次单击时,该方法运行两次(通过向控制台发送的两条消息验证);第三次运行三遍,依此类推。

main.js中用于扫描目录的函数每次单击仅运行一次,因此问题必须在inteface.js中。

我的main.js和interface.js代码:

main.js:

const {app, BrowserWindow, ipcMain} = require('electron');
const fs = require('fs');

...

ipcMain.on( 'list-directory', ( event, directory ) => {
    var files = fs.readdirSync( directory );
    event.sender.send( 'list-directory-reply', files );
});

interface.js

var { ipcRenderer, remote } = require( 'electron' );  
var main = remote.require( "./main.js" );

...

button.addEventListener('click', function(){ showDialogue( this ); }, false );

...

showDialogue( select ) {
    // clear the dialogue
    // some other stuff
    ipcRenderer.send( 'list-directory', './files/documents/' );
    ipcRenderer.on( 'list-directory-reply', function( event, contents ) {
        console.log( contents );
        if ( contents.length > 0 ) {
            // add contents to the dialogue
        }
    } );
}

该代码改编自Electron网站上的教程。

ipcRenderer.on为什么要多次运行?每次单击按钮时,它是否都可能绑定到某物,因此其运行次数与过去的点击次数相同?我在事件监听器中和showDialogue之前的ipcRenderer函数中放置了一条print语句,但是它们每次都只打印一次,因此重复肯定只来自ipcRenderer.on

2 个答案:

答案 0 :(得分:2)

正如@planet_hunter所述,您每次调用showDialogue()时都在建立一个侦听器。您需要删除侦听器或将侦听器移到调用函数之外。

但是,我发现一种更干净的解决方案是使用.once命令。行为类似于.on,但是它无需删除.on侦听器(您尚未完成),而是将其自身删除。

showDialogue( select ) {
    // clear the dialogue
    // some other stuff
    ipcRenderer.send( 'list-directory', './files/documents/' );
    ipcRenderer.once( 'list-directory-reply', function( event, contents ) {
        console.log( contents );
        if ( contents.length > 0 ) {
            // add contents to the dialogue
        }
    } );
}

答案 1 :(得分:1)

每次引起多个订阅的按钮单击后,您正在订阅ipcRenderer.on。尝试在click事件之外定义ipcRenderer.on事件处理程序,它应该可以正常工作。

类似的东西-

button.addEventListener('click', function(){ showDialogue( this ); }, false );


ipcRenderer.on( 'list-directory-reply', function( event, contents ) {
    // ipcRenderer event handler
});

showDialogue(select) {
    ipcRenderer.send( 'list-directory', './files/documents/' );
}