Node .on 方法触发太多次

jla*_*jla 6 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 代码:

主要.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 );
});
Run Code Online (Sandbox Code Playgroud)

接口.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
        }
    } );
}
Run Code Online (Sandbox Code Playgroud)

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

为什么ipcRenderer.on运行多次?是否有可能每次单击按钮时它都会绑定到某些东西,从而与过去的点击次数一样多?我在事件侦听器函数中以及在东西showDialogue之前的函数中放置了一个打印语句ipcRenderer,但是它们每次单击都只打印一次,因此重复肯定只来自ipcRenderer.on.

pla*_*ter 6

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

像这样的东西——

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/' );
}
Run Code Online (Sandbox Code Playgroud)


psi*_*i75 5

正如@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
        }
    } );
}
Run Code Online (Sandbox Code Playgroud)