繁体   English   中英

在不使用async / await的情况下使用诺言时,电子打开对话框会挂起

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM