从 Electron Container IPC Channel 接收数据时,Change Detection 会间歇性工作

Posted

技术标签:

【中文标题】从 Electron Container IPC Channel 接收数据时,Change Detection 会间歇性工作【英文标题】:Change Detection works intermittently when receiving data from Electron Container IPC Channel 【发布时间】:2019-11-24 15:35:18 【问题描述】:

我有一个应用程序正在侦听来自 IPC 渲染器通道的​​传入数据。这是我的设置:

将数据发送到 Angular 应用程序的容器(主窗口):

mainWindow.loadURL('http://www.myangularapp.com') //where the angular app lives (example url).
mainWindow.webContents.on('did-finish-load', () => 
      const data =  name: "John Doe", address: "123 Main St", city: "NY"
      mainWindow.webContents.send('data-from-container', data)
        
    )

角度应用:

constructor(
    private store: Store<fromStore.AppState>,
    private cd: ChangeDetectorRef,
    private zone: NgZone,
  ) 

  ngOnInit() 
this.isLoading = true;
    if (this.electronService.ipcRenderer) 
      this.electronService.ipcRenderer.on('data-from-container', (event, data) => 
        this.zone.run(() => 
          if(data)
            setTimeout(() => 
              console.log(data) // verified data is always received
              this.formData = data; // property that form uses to populate data in the dom
              this.prepopulateForm(data) // method that places incoming data in ngrx store
            , 1000)
          
        )
      )
    

    this.store.select('containerData').subscribe(data => 
        setTimeout(()=> 
          console.log(data) // data is always being set in ngrx
          this.isLoading = false
        , 5000);
    )

  

每次 IPC 通道发出 'data-from-container' 事件时,数据总是从我的 OnInit 调用中接收,但数据并不总是在我的表单中设置!我注意到的模式通常是,当 Angular 应用程序首次在容器内启动时,数据不会预先填充表单,在初始启动后,每次启动应用程序时,数据都会出现。

我尝试使用 ngZone、setTimeout 和 detectChange 方法来触发更改检测,以便 Angular 应用程序可以检测到新设置的 formData,但它并不能始终如一地预填充表单。有关如何解决此问题的任何建议?

【问题讨论】:

试试:if (data) setTimeout(() =&gt; this.zone.run(() =&gt; this.formData = data; ... ); , 1000); . 还是一样的结果:/ 你为什么在zone.run里面使用setTimeout 能否展示所有与表单和数据绑定相关的代码? 如果你能用最少的可重现代码创建一个 git repo,我相信提供一个解决方案会很容易 【参考方案1】:

我对电子有非常基本的了解,所以我会尝试向您展示这个想法。对我来说,您的问题来自视图的初始化。您不会丢失事件,因为您可以在控制台中看到它们,但在视图中看不到,这加强了我的猜测。

如您的代码所示,您只发送一个事件(我想它只是为了测试原因),我们希望在呈现视图时显示它。

在您的组件中添加一个主题,通知我们视图已初始化,例如:

import  Subject, combineLatest, fromEvent  from 'rxjs';

viewInitialized$ = new Subject();

...

ngAfterViewInit() 
 this.viewInitialized$.next();


...

现在我们可以等待两个发射,一个来自ipcRenderer,另一个来自viewInitialized$,使用combineLatest运算符。

在此之前,我们必须将ipcRenderer 转换为Observable。从这个SO 响应我们可以做fromEvent(ipcRenderer,'data-from-container')。如果它不起作用,我们可以使用另一个主题,每次我们在ipcRenderer.on() 中收到某些内容时都会发出事件,第二种解决方案需要 ngZone。


ngOnInit() 
...

const containerData$ = fromEvent(this.electronService.ipcRenderer, 'data-from-container');
this.subscription = combineLatest(containerData$, this.viewInitialized$).subscribe(combined => 
  const data = combined[0];
  this.formData = data;
  this.prepopulateForm(data) 
)

...


ngOnDestroy() 
  this.subscription.unsubscribe();

希望这会有所帮助。

【讨论】:

以上是关于从 Electron Container IPC Channel 接收数据时,Change Detection 会间歇性工作的主要内容,如果未能解决你的问题,请参考以下文章

Electron - IPC - 在窗口之间发送数据

通过 Electron 的 IPC 渲染器发送敏感数据

javascript、electron、ipc 不给出错误或输出

Electron IPC 和节点集成

从并发处理谈PHP进程间通信System V IPC

如何使Electron进行IPC 通信?