Skip to content

Instantly share code, notes, and snippets.

@typoerr
Created July 22, 2017 14:23
Show Gist options
  • Save typoerr/a96e07114b2e368eea25c1fe2e16cd93 to your computer and use it in GitHub Desktop.
Save typoerr/a96e07114b2e368eea25c1fe2e16cd93 to your computer and use it in GitHub Desktop.
worker-utils
declare var navigator: Navigator;
// navigator.serviceWorker.readyはactivate直前に発火するため、controllerの存在確認には信用できない
// そのためcontrollerchangeイベントを待つ必要がある
export default function awaitServiceWorker() {
return new Promise<ServiceWorker>((resolve) => {
const resolved = () => resolve(navigator.serviceWorker.controller!);
if (navigator.serviceWorker.controller) {
resolved();
} else {
navigator.serviceWorker.addEventListener('controllerchange', resolved);
}
});
}
import Minitter from 'minitter';
export type ResponseMap<T, C> = {
[K in keyof T]: MessageRequestEvent<T, C, K>
};
export interface Action<T, K extends keyof T> {
type: K;
payload: T[K];
}
type Port = { postMessage: Function };
export class MessageRequestEvent<T, C, K extends keyof T> {
type: K;
data: T[K];
context: C;
private ports: Port[] = [];
constructor(action: Action<T, K>, context: C, ports?: Port[] | null) {
this.type = action.type;
this.data = action.payload;
this.context = context;
this.ports = ports || [];
}
res<K2 extends keyof T>(type: K2, payload: T[K2]) {
const r = JSON.stringify({ type, payload });
this.ports.forEach(port => port.postMessage(r));
}
}
export class Messenger<T, C = any> extends Minitter<ResponseMap<T, C>> { }
/*
# Example
---------------------------------------------------
interface Messages {
'worker:request:a': string;
'worker:resolved:a': number;
'worker:error:a': Error
}
const messenger = new Messenger<Messages>();
self.addEventListener('message', ev => {
self.clients.matchAll().then(list => {
const action = JSON.parse(ev.data)
messenger.emit(action.type, new ResponseEvent(action, {}, list))
})
})
messenger.on('a', e => {
return someAsyncFunction(e.data)
.then(x => e.response('worker:resolved:a', x))
.catch(err => e.response('worker:error:a', err))
});
*/
export type TypedMessageWorker<T> = (Worker | ServiceWorker) & {
request<K extends keyof T>(type: K, payload: T[K]): void;
};
export default function enhance<T = any>(worker: Worker | ServiceWorker): TypedMessageWorker<T> {
function request<K extends keyof T>(type: K, payload: T[K]) {
const action = JSON.stringify({ type, payload });
worker.postMessage(action);
}
return Object.assign(worker, { request });
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment