[英]Electron open dialog hangs when using promise without async/await
电子打开对话框窗口出现非常奇怪的错误。 每当我打开它时,它就会挂起并且应用程序冻结。
逻辑很简单,我有一个使用typescript-fsa
库创建异步操作的助手。 它的目的是调用一个promise,并在完成时调用已完成/失败的操作。 这个帮助程序不是问题,因为它可用于应用程序中的其他100个史诗,但它可能会与电子对话框发生冲突。
export function makeAsyncEpic<T, P, S>(
actionCreator: AsyncActionCreators<T, P, S>,
asyncMethod: (params: T, state: ApplicationState, action$) => Promise<P>,
filter?: (action$: Observable<Action>, state: ApplicationState) => boolean,
) {
return makeObservableEpic(actionCreator, (p, s, a) => Observable.fromPromise(asyncMethod(p, s, a)), filter);
}
export function makeObservableEpic<T, P, S>(
{ started, done, failed }: AsyncActionCreators<T, P, S>,
observable: (params: T, state: ApplicationState, action$) => Observable<P>,
filter?: (action$: Observable<Action>, state: ApplicationState) => boolean,
) {
return (action$: Observable<Action>, store: { getState: () => ApplicationState }) =>
action$
.filter(started.match)
.filter(() => (filter === undefined ? true : filter(action$, store.getState())))
.switchMap(action =>
observable(action.payload, store.getState(), action$)
.map(result => {
return done({
params: action.payload,
result,
});
})
.catch(error => {
return Observable.of(
failed({
params: action.payload,
error,
}),
);
}),
);
}
当我调用action.openRepository.started时,以下史诗冻结了该应用程序:
const remote = electron.remote;
const mainProcess = remote.require("./dialog");
export const openDirectoryEpic = makeAsyncEpic(actions.openRepository, mainProcess.openDirectory);
令人惊讶的是,如果我将其更改为
export const openDirectoryEpic = makeAsyncEpic(actions.openRepository, async () => {
const directory = await mainProcess.openDirectory();
return directory;
});
工作正常。 它不是等效的吗? 可能的原因是什么?
编辑:
我什至可以在这里删除async / await,并像这样放置它并起作用:
export const openDirectoryEpic1 = makeAsyncEpic(actions.openRepository, () => mainProcess.openDirectory());
() => mainProcess.openDirectory()
等同于mainProcess.openDirectory
吗?
EDIT2:openDirectory是通过以下方式实现的:
import { dialog, ipcMain } from "electron";
import { mainWindow } from "./main";
export const openDirectory = (): Promise<{ directory: string }> =>
new Promise((resolve, reject) => {
console.log("Opening dialog");
const property: "openDirectory" = "openDirectory";
const options = {
title: "Select Repository",
properties: [property],
};
try {
dialog.showOpenDialog(mainWindow, options, (files: string[]) => {
if (files && files.length === 1) {
resolve({ directory: files[0] });
} else {
reject(`Error when opening directory: ${files}`);
}
});
} catch (err) {
reject(err);
}
});
使用makeAsyncEpic(actions.openRepository, mainProcess.openDirectory);
您隐式地将所有参数传递给openDirectory函数, electron.remote
需要打包/包装每个参数,然后才能将其发送到主处理器。 在您的情况下,最后一个参数是Observable
类型,而Electron打包时可能会遇到问题。
使用makeAsyncEpic(actions.openRepository, () => mainProcess.openDirectory())
您无需将任何参数传递给openDirectory
函数,因此Electron不会出现任何问题。
我猜测以下语法(p, s, a) => mainProcess.openDirectory(p, s, a)
会引起与第一个相同的问题。
openDirectory()
在哪里?
docs指出showOpenDialog
是同步的,除非您传递了回调。
如果要调用showOpenDialog
并使其返回约定,则必须正确包装它。 这是我们从渲染器执行的操作,它不会挂起:
const { remote } = require('electron');
public selectDirectory(mainWindow: BrowserWindow, defaultPath: string): Promise<string> {
return new Promise<string>((resolve, reject) => {
remote.dialog.showOpenDialog(mainWindow, {
properties: ['openDirectory'],
defaultPath: defaultPath
}, names => {
resolve(names ? names[0] : undefined);
});
});
}
当使用remote
,您可能需要注意一件事: 您正在要求同步操作 。
https://github.com/electron/electron/blob/master/docs/api/remote.md#remote-objects
当您调用远程对象的方法,调用远程函数或使用远程构造函数(函数)创建新对象时,实际上是在发送同步的进程间消息。
如果您希望具有异步行为,请不要在进程和主进程之间使用remote
设置异步ipc通道来让异步异步ipc请求行为。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.