【问题标题】:Electron / NodeJS and application freezing on setInterval / async codeElectron / NodeJS 和 setInterval / async 代码上的应用程序冻结
【发布时间】:2017-03-30 17:36:59
【问题描述】:

我正在开发一个electron 应用程序,该应用程序使用电子 API 每 3 秒执行一次屏幕截图捕获,并将其写入给定的目标路径。我已经设置了一个单独的 BrowserWindow,捕获代码在其中运行(参见下面的代码结构)一个 setInterval()“循环”,但是每当捕获发生时,应用程序都会冻结片刻。我认为是在文件ScreenCapturer.jshtml.js 中调用source.thumbnail.toPng()writeScreenshot() 方法。

我设置了这个结构,因为我认为这是要走的路,但显然不是这样。 WebWorkers 也帮不了我,因为我需要 fs、path 和 desktopCapturer 等节点模块(来自 electron)。

如何在每次间隔代码(如文件ScreenCapturer.jshtml.js 中所见)运行时不阻塞主线程的情况下执行此类任务(因为我认为渲染器进程是单独的进程?)


我的代码作为参考

ma​​in.js(主进程)

// all the imports and other
// will only show the import that matters
import ScreenCapturer from './lib/capture/ScreenCapturer';  

app.on('ready', () => {
   // Where I spawn my main UI
   mainWindow = new BrowserWindow({...});
   mainWindow.loadURL(...);
   // Other startup stuff

   // Hee comes the part where I call function to start capturing
   initCapture();
});

function initCapture() {
    const sc = new ScreenCapturer();
    sc.startTakingScreenshots();
}

ScreenCapturer.js(主进程使用的模块)

'use strict';

/* ******************************************************************** */
/* IMPORTS */
import { app, BrowserWindow, ipcMain } from 'electron';
import url from 'url';
import path from 'path';
/* VARIABLES */
let rendererWindow;
/*/********************************************************************///
/*///*/

/* ******************************************************************** */
/* SCREENCAPTURER */
export default class ScreenCapturer {
    constructor() {
        rendererWindow = new BrowserWindow({
            show: true, width: 400, height: 600,
            'node-integration': true,
            webPreferences: {
                webSecurity: false
            }
        });                        
        rendererWindow.on('close', () => {
            rendererWindow = null;
        });
    }

    startTakingScreenshots(interval) {
        rendererWindow.webContents.on('did-finish-load', () => {
            rendererWindow.openDevTools();
            rendererWindow.webContents.send('capture-screenshot', path.join('e:', 'temp'));
        }); 
        rendererWindow.loadURL(
            url.format({
                pathname: path.join(__dirname, 'ScreenCapturer.jshtml.html'),
                protocol: 'file:',
                slashes: true
            })
        );                       
    }    
}
/*/********************************************************************///
/*///*/

ScreenCapturer.jshtml.js(渲染器浏览器窗口中加载的 thml 文件)

<html>
    <body>
        <script>require('./ScreenCapturer.jshtml.js')</script>
    </body>
</html>

ScreenCapturer.jshtml.js(渲染器进程中从html文件加载的js文件)

import { ipcRenderer, desktopCapturer, screen } from 'electron';
import path from 'path';
import fs from 'fs';
import moment from 'moment';
let mainSource;

function getMainSource(mainSource, desktopCapturer, screen, done) {
    if(mainSource === undefined) {
        const options = {
            types: ['screen'],
            thumbnailSize: screen.getPrimaryDisplay().workAreaSize
        };
        desktopCapturer.getSources(options, (err, sources) => {
            if (err) return console.log('Cannot capture screen:', err);
            const isMainSource = source => source.name === 'Entire screen' || source.name === 'Screen 1';
            done(sources.filter(isMainSource)[0]);        
        });
    } else {
        done(mainSource);
    }
}
function writeScreenshot(png, filePath) {
    fs.writeFile(filePath, png, err => {        
        if (err) { console.log('Cannot write file:', err); }
        return;       
    });
}

ipcRenderer.on('capture-screenshot', (evt, targetPath) => {    
    setInterval(() => {          
        getMainSource(mainSource, desktopCapturer, screen, source => {
            const png = source.thumbnail.toPng();
            const filePath = path.join(targetPath, `${moment().format('yyyyMMdd_HHmmss')}.png`);
            writeScreenshot(png, filePath);
        });
    }, 3000);
});

【问题讨论】:

标签: node.js multithreading asynchronous electron


【解决方案1】:

我不再使用由 electron 提供的 API。我建议使用desktop-screenshot 包-> https://www.npmjs.com/package/desktop-screenshot。这对我来说是跨平台的(linux、mac、win)。 注意windows 我们需要hazardous package,否则当使用asar 打包您的电子应用程序时,它将无法执行desktop-screenshot 中的脚本。有关危险包装页面的更多信息。

以下是我的代码现在大致如何工作,请不要复制/粘贴,因为它可能不适合您的解决方案!但是,它可能会提示您如何解决它。

/* ******************************************************************** */
/* MODULE IMPORTS */
import { remote, nativeImage } from 'electron';
import path from 'path';
import os from 'os';
import { exec } from 'child_process';
import moment from 'moment';
import screenshot from 'desktop-screenshot';
/* */
/*/********************************************************************///
/* ******************************************************************** */
/* CLASS */
export default class ScreenshotTaker {    
    constructor() {
        this.name = "ScreenshotTaker";        
    }
    start(cb) {
        const fileName = `cap_${moment().format('YYYYMMDD_HHmmss')}.png`;
        const destFolder = global.config.app('capture.screenshots');
        const outputPath = path.join(destFolder, fileName);        
        const platform = os.platform();
        if(platform === 'win32') {
            this.performWindowsCapture(cb, outputPath);
        }
        if(platform === 'darwin') {
            this.performMacOSCapture(cb, outputPath);
        }
        if(platform === 'linux') {
            this.performLinuxCapture(cb, outputPath);
        }
    }
    performLinuxCapture(cb, outputPath) {
        // debian
        exec(`import -window root "${outputPath}"`, (error, stdout, stderr) => {
            if(error) {
                cb(error, null, outputPath);
            } else {
                cb(null, stdout, outputPath);
            }
        });
    }
    performMacOSCapture(cb, outputPath) {
        this.performWindowsCapture(cb, outputPath);
    }
    performWindowsCapture(cb, outputPath) {
        require('hazardous');
        screenshot(outputPath, (err, complete) => {
            if(err) {
                cb(err, null, outputPath);
            } else {
                cb(null, complete, outputPath);
            }
        });
    }
}
/*/********************************************************************///

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-15
    • 2011-08-16
    • 2018-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-29
    • 2018-01-15
    相关资源
    最近更新 更多