我遇到了非常奇怪的错误与电子打开对话框窗口。每当我打开它,它就会挂起,应用程序就会被冻结。
逻辑很简单,我有一个用typescript-fsa库创建异步操作的助手。它的目的是调用一个承诺,当它完成时,调用已完成的/失败的行动。这不是这个助手的问题,因为它适用于应用程序中的其他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,
}),
);
}),
);
}当我调用actions.openRepository.started时,以下epic会冻结应用程序:
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;
});效果很好。这不是等价的吗?可能的原因是什么?
编辑:
我甚至可以删除异步/等待在这里,并将它这样说,它是有效的:
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);
}
});发布于 2018-03-13 19:00:37
使用makeAsyncEpic(actions.openRepository, mainProcess.openDirectory);,您可以隐式地将所有参数传递给openDirectory函数,而electron.remote需要打包/包装每个参数,然后才能将其发送到主处理器。在您的例子中,最后一个参数是Observable类型,电子在打包时可能会有问题。
使用makeAsyncEpic(actions.openRepository, () => mainProcess.openDirectory()),您不会向openDirectory函数传递任何参数,因此电子不会有任何问题。
我猜下面的语法(p, s, a) => mainProcess.openDirectory(p, s, a)将导致与第一个语法相同的问题。
发布于 2018-03-13 17:10:17
openDirectory()在哪里?
文档状态,除非您传递回调,否则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);
});
});
}发布于 2018-03-12 21:45:00
当您使用remote时,您可能需要注意一件重要的事情:您要求的是同步操作。
https://github.com/electron/electron/blob/master/docs/api/remote.md#remote-objects
当调用远程对象的方法、调用远程函数或使用远程构造函数(函数)创建新对象时,实际上是在发送同步进程间消息。
如果您希望有异步行为,而不是在进程和让主进程之间使用remote安装异步ipc通道来处理异步ipc请求。
https://stackoverflow.com/questions/49241837
复制相似问题