举一个例子,在 electron 的 renderer 中,使用 ipcRenderer 来做通信,为了效率起见,一般使用异步的 send
方法.
这种情况下,如果是应答式的通信,main 进程发回的通信是不方便在同一个逻辑中完成的(当然也可以在这里listen channel,但是实现起来很奇怪,并且逻辑也不清晰),因此一般都是统一管理。
如果使用 Subject
来做异步处理,会非常方便。
用如下 service 来做样例。
import { Injectable, NgZone } from '@angular/core';
import { Observable, Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class TaskService {
// 这个 map 用来保存所有 Subject
tasks = new Map<string, Subject<any>>();
constructor(private zone: NgZone) {
if (navigator.userAgent.toLowerCase().indexOf(' electron/') > -1) {
const {ipcRenderer} = window.require('electron');
ipcRenderer.on('demo', (event, data) => {
// 收到服务端返回之后,找对应的 subject,传入返回值,subscriber 就可以继续进行
if (data.uuid && this.tasks.has(data.uuid)) {
const subject = this.tasks.get(data.uuid);
// 由于异步方法不在 zone 中,假如 subscriber 中有对 view 的操作,将无法正常更新,这里简单通过 zone.run 确保 subscriber 的正确执行
this.zone.run(() => {
subject.next(data);
});
// complete 解除所有 subscriber
subject.complete();
this.tasks.delete(data.uuid);
}
});
}
}
send(param: string): Observable<any> {
if (navigator.userAgent.toLowerCase().indexOf(' electron/') > -1) {
const {ipcRenderer} = window.require('electron');
// renderer 和 main 之间的通信,通过 uuid 来做通信唯一 ID,main 回复的时候会返回这个 uuid
const uuid = uuidv4();
const fullParam = {
uuid,
param,
};
ipcRenderer.send('demo', fullParam);
// 发送之后返回 Subject,这样调用的地方就可以直接 subscribe
const subject = new Subject();
this.tasks.set(uuid, subject);
return subject.asObservable();
}
}
}