javascript - 使用没有 async/await 的 Promise 时, Electron 打开对话框会挂起

标签 javascript reactjs typescript redux electron

我在 Electron 打开对话框窗口中遇到非常奇怪的错误。每当我打开它时,它就会挂起并且应用程序被卡住。

逻辑很简单,我有一个使用 typescript-fsa 库创建异步操作的助手。它的目的是调用一个 promise ,并在完成时调用完成/失败的操作。这不是这个助手的问题,因为它适用于应用程序中的其他 100 个史诗,但它可能会做一些与 Electron 对话框冲突的事情。

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 时,以下史诗卡住了应用程序:

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需要先打包/package 每个参数,然后才能将其发送到主处理器。 在您的情况下,最后一个参数是 Observable type 和 Electron 在打包时可能会出现问题。

使用makeAsyncEpic(actions.openRepository, () => mainProcess.openDirectory())您没有将任何参数传递给 openDirectory函数所以 Electron 不会有任何问题。

我猜测以下语法 (p, s, a) => mainProcess.openDirectory(p, s, a)将导致与第一个相同的问题。

关于javascript - 使用没有 async/await 的 Promise 时, Electron 打开对话框会挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49241837/

相关文章:

javascript - 带 typescript 的 Angular Material 设计

javascript - Angular 2 数组打印在控制台上,但无法在屏幕上打印对象属性

javascript - 在 Javascript 中查找 (x,y) 坐标处的元素(最高可见元素)

javascript - Chrome 扩展程序简单音频

reactjs - 在 componentDidMount 中触发重新渲染

reactjs - 单元测试 : Actions must be plain objects. 使用自定义中间件进行异步操作

angular - 数组中的通用类型?

javascript - 数据绑定(bind)的主要例子

javascript - 无法从客户端将文件数据发送到nodejs服务器

asp.net-mvc - Angularjs 轻型版本