Mit WebWorkern existiert im Browser eine Möglichkeit, zeitaufwendige Aufgaben in einen Hintergrund-Thread zu verlagern, ohne die UI zu blockieren. Zwar haben WebWorker keine Zugriffsmöglichkeit auf das DOM, können aber auch dazu genutzt werden, um Daten zwischen Anwendung-Tabs aus zu tauschen (via SharedWorker).
Mit einem solchen SharedWorker ließe sich nun z.B. ein Tab-übergreifender Logout durchführen. Dazu registrieren wir lediglich einen SharedWorker, der dafür sorgt, dass alle registrierten Ports (Tabs, Services) benachrichtigt werden, wenn ein Logout stattfindet. Dazu wird der Worker in einer separaten Datei deklariert. Dieser übernimmt lediglich die Weitergabe der Logout-Nachricht:
let ports = [];
onconnect = function (e) {
const port = e.ports[0];
ports.push(e.ports[0]);
port.onmessage = function (event) {
const {action} = event.data;
switch (action) {
case 'logout':
ports.forEach(port => port.postMessage({action: 'logout'}));
break;
case 'closeConnection':
const index = ports.indexOf(port);
if (index > -1) ports.splice(index, 1);
break;
break;
}
};
};
Unser Angular Service registriert sich nun und verarbeitet entsprechend eingehende Nachrichten und führt einen Logout bzw. eine Umleiten auf die Login-Seite in diesem Tab durch:
private initLogoutWorker() {
this.worker = new SharedWorker('/webworker/auth-worker.js');
this.port = this.worker.port;
this.port.onmessage = (event) => {
const {action} = event.data;
switch (action) {
case 'logout':
if (this.oauthService.hasValidAccessToken()) {
this.oauthService.logOut();
} else {
this.router.navigateByUrl('/login');
}
break;
}
};
this.port.start();
window.addEventListener('beforeunload', () => this.ngOnDestroy());
}
Der eigentliche Logout würde (in einem beliebigen Tab getriggert) eine entsprechende Nachricht verschicken, die von allen angemeldeten Ports (unsere Anwendung in mehrere Tabs) verarbeitet werden und zum gewünschten Logout führt.
// logout verarbeiten, hier via OAuth-Service-Event
this.oauthService.events.pipe(
filter(e => e.type === 'logout')
).subscribe(() => this.port.postMessage({action: 'logout'}));
}





