首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无异步/等待使用承诺时电子打开对话框挂起

无异步/等待使用承诺时电子打开对话框挂起
EN

Stack Overflow用户
提问于 2018-03-12 18:09:11
回答 3查看 1.7K关注 0票数 0

我遇到了非常奇怪的错误与电子打开对话框窗口。每当我打开它,它就会挂起,应用程序就会被冻结。

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

代码语言:javascript
复制
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会冻结应用程序:

代码语言:javascript
复制
const remote = electron.remote;
const mainProcess = remote.require("./dialog");

export const openDirectoryEpic = makeAsyncEpic(actions.openRepository, mainProcess.openDirectory);

令人惊讶的是如果我把它改成

代码语言:javascript
复制
export const openDirectoryEpic = makeAsyncEpic(actions.openRepository, async () => {
  const directory = await mainProcess.openDirectory();
  return directory;
});

效果很好。这不是等价的吗?可能的原因是什么?

编辑:

我甚至可以删除异步/等待在这里,并将它这样说,它是有效的:

代码语言:javascript
复制
export const openDirectoryEpic1 = makeAsyncEpic(actions.openRepository, () => mainProcess.openDirectory());

不是() => mainProcess.openDirectory()等价于mainProcess.openDirectory

EDIT2: openDirectory是以这种方式实现的:

代码语言:javascript
复制
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);
    }
  });
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 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)将导致与第一个语法相同的问题。

票数 2
EN

Stack Overflow用户

发布于 2018-03-13 17:10:17

openDirectory()在哪里?

文档状态,除非您传递回调,否则showOpenDialog是同步的。

如果您想调用showOpenDialog并让它返回承诺,则必须正确包装它。这就是我们从渲染器中所做的,它不会挂起:

代码语言:javascript
复制
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);
    });
  });
}
票数 1
EN

Stack Overflow用户

发布于 2018-03-12 21:45:00

当您使用remote时,您可能需要注意一件重要的事情:您要求的是同步操作。

https://github.com/electron/electron/blob/master/docs/api/remote.md#remote-objects

当调用远程对象的方法、调用远程函数或使用远程构造函数(函数)创建新对象时,实际上是在发送同步进程间消息。

如果您希望有异步行为,而不是在进程和让主进程之间使用remote安装异步ipc通道来处理异步ipc请求。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49241837

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档