workerable
Version:
A wrapper around SharedWorker to provide a single synced store between browser tabs or windows
68 lines (55 loc) • 2.59 kB
JavaScript
;
var workerUrl = "data:application/javascript;base64,Y29uc3QgcG9ydHMgPSBuZXcgU2V0KCk7CmxldCBkYXRhID0gbnVsbDsKCmZ1bmN0aW9uIGJyb2FkY2FzdEFsbCh0eXBlLCBkYXRhKSB7CiAgcG9ydHMuZm9yRWFjaChwb3J0ID0+IHsKICAgIHBvcnQucG9zdE1lc3NhZ2UoW3R5cGUsIGRhdGFdKTsKICB9KTsKfQoKZnVuY3Rpb24gYnJvYWRjYXN0T3RoZXIodGhpc1BvcnQsIHR5cGUsIGRhdGEpIHsKICBwb3J0cy5mb3JFYWNoKHBvcnQgPT4gewogICAgaWYgKHBvcnQgPT09IHRoaXNQb3J0KSByZXR1cm47CiAgICBwb3J0LnBvc3RNZXNzYWdlKFt0eXBlLCBkYXRhXSk7CiAgfSk7Cn0KCmZ1bmN0aW9uIG1zZ0hhbmRsZXIoZSkgewogIGNvbnN0IFt0eXBlLCBfZGF0YV0gPSBlLmRhdGE7CiAgc3dpdGNoICh0eXBlKSB7CiAgICBjYXNlICdzZXQnOgogICAgICBkYXRhID0gX2RhdGE7CiAgICAgIGJyb2FkY2FzdE90aGVyKHRoaXMsICdzZXQnLCBkYXRhKTsKICAgICAgYnJlYWs7CiAgICBjYXNlICdpbml0JzoKICAgICAgaWYgKHBvcnRzLnNpemUgPT09IDApIHsKICAgICAgICBkYXRhID0gX2RhdGE7CiAgICAgIH0KICAgICAgYnJlYWs7CiAgICBjYXNlICdjbG9zZSc6CiAgICAgIHBvcnRzLmRlbGV0ZSh0aGlzKTsKICAgICAgYnJlYWs7CiAgICBkZWZhdWx0OgogICAgICByZXR1cm47CiAgfQp9CgpzZWxmLmFkZEV2ZW50TGlzdGVuZXIoJ2Nvbm5lY3QnLCBmdW5jdGlvbihlKSB7CiAgaWYgKCFlLnBvcnRzIHx8ICFlLnBvcnRzLmxlbmd0aCkgcmV0dXJuOwogIGNvbnN0IHBvcnQgPSBlLnBvcnRzWzBdOwogIHBvcnQuc3RhcnQoKTsKICBwb3J0LmFkZEV2ZW50TGlzdGVuZXIoJ21lc3NhZ2UnLCBtc2dIYW5kbGVyKTsKICBwb3J0cy5hZGQocG9ydCk7CiAgaWYgKHBvcnRzLnNpemUgPiAxKSB7CiAgICBwb3J0LnBvc3RNZXNzYWdlKFsnc2V0JywgZGF0YV0pOwogIH0KfSk7Cg==";
function sharedWritable(init, startTrigger) {
const worker = new SharedWorker(workerUrl);
worker.port.start();
worker.port.postMessage(['init', init]);
worker.port.addEventListener('message', messageHandler);
const subs = new Set();
let stopTrigger = null;
let data = init;
function notifyAll() {
subs.forEach(cb => {
cb(data);
});
}
function subscribe(callback) {
callback(data);
subs.add(callback);
if (subs.size === 1 && typeof startTrigger === 'function') {
stopTrigger = startTrigger(set);
}
return () => {
subs.delete(callback);
if (subs.size === 0 && typeof stopTrigger === 'function') {
stopTrigger();
worker.port.postMessage(['close']);
}
};
}
function set(_data) {
if (_data === data) return;
data = _data;
worker.port.postMessage(['set', data]);
notifyAll();
}
function update(callback) {
const newData = callback(data);
if (newData === data) return;
data = newData;
worker.port.postMessage(['set', data]);
notifyAll();
}
function messageHandler(e) {
const [type, _data] = e.data;
if (type === 'set') {
set(_data);
}
}
return {
subscribe,
set,
update
};
}
module.exports = sharedWritable;