Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.2k views
in Technique[技术] by (71.8m points)

javascript - ElectronJS: logging method fires multiple times when don't wanted when using invoke/handle

As the title states. I have this problem with my ElectronJS project. When I try to log an output from an invoked handler, the logging happens multiple times, even though the function is run only once. What could be the cause of this?

The function is run only once, for each class object created. See GIF at the bottom to see the problem "in action".

I have tried removing the handler and listeners, but that just makes it so that the next object won't be able invoke downloadPoster..

Thanks in advance for any help.

Here is how the objects are instanciated and "processed".

// On drop
window.ondrop = async function(e) {
    e.preventDefault();
    body.classList.remove('file-hover');
    for (var [i, file] of Object.entries(e.dataTransfer.files)) {
        var x = new Movie(file.path);
        await x.process();
    }
    return false;
};

? Here is the function from the class in renderer.js

/**
* Download poster file for movie
*/
async downloadPoster() {

    // This is the url used to search for the poster we want
    var searchUrl = new URL(Config.api.searchUrl);
    searchUrl.search = new URLSearchParams({
        page: 1, 
        api_key: Config.api.key,
        query: this.#movie.tags.title,
        year: this.#movie.tags.year
    });

    // Search for poster in the main thread
    await axios.get(searchUrl.href)
    .then(async (resp) => {

        // No results
        if (resp.data.total_results <= 0) {
            this.log('No poster found', 'error');
            return;
        } 
            
        // Invoke poster download
        const result = await ipcRenderer.invoke('downloadPoster', {
            src: Config.api.posterUrl + resp.data.results[0].poster_path,
            dest: path.join(this.#movie.new.absolutePath, Config.api.posterFilename)
        })
        
        // This shows "undefined"    
        this.log(result);

    })
    .catch(async (err) => {
            this.log('Could not search for poster: ' + err, 'error');
    });

} 

Here is the handler function from the main.js

// Download poster
ipcMain.handle('downloadPoster', async (event, args) => {

    await axios.get(args.src, { responseType: 'stream' })
    .then(async (resp) => {

        const writeStream = fs.createWriteStream(args.dest);

        // Write data to file
        await resp.data.pipe(writeStream);
        
        // When finished, send reply back
        writeStream.on('finish', async () => {
            return {
                success: true,
                message: 'Poster downloaded'
            }
        });

        // On error writing, send reply back
        writeStream.on('error', async (err) => {
            return {
                success: false,
                message: 'Could not write poster to file: ' + err
            }
        });

    })
    .catch(async (err) => {
        return {
            success: false,
            message: 'Could not download poster: ' + err
        }
    });

});

No actual pirated material. Just test folders.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You may be misunderstanding invoke/handle. The whole point of using that feature is that the return value from the handler in the main process is returned by the invoke method in the renderer. So you can do this:

// main.js
ipcMain.handle('some-command', async (evt, data) => {
// do something with data, the handler can also be async
 const value = await getSomeValue();
 return doSomething(data, value);
}
// renderer.js
(async () => {
 const invokeReturn = await ipcRenderer.invoke('some-command', data);
 // invokeReturn will contain the result of doSomething(data, value) from main
})

I would need to do some debugging on your code to be sure but my instinct is that the behavior is caused by this bit of code:

// Poster download reply from the invoke above
ipcRenderer.on('downloadPosterReply', async (event, args) => {

You're setting a listener and never removing it, so with each function call there's a new handler added, causing more and more logs to appear. Thanks to invoke/handle, you don't need to use an on handler here at all.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...