Published
Edited
Apr 20, 2022
Importers
Insert cell
Insert cell
function newService() {
let values;
let providers = []
let consumers = [];
const service = function() {
if (!values) { values = providers.map(_ => _.value).filter(v => v !== undefined); }
return values
};
function notify() { const v = service(); consumers.forEach(c => c.listener && c.listener(v)); }
service.closed = false;

service.close = function close() {
service.closed = true;
values = null;
service.newProvider = service.newConsumer = () => { throw new Error('Service is closed'); };
consumers.forEach(c => c.close());
providers.forEach(p => p.close());
providers = consumers = [];
}

service.newProvider = function newProvider(initial) {
const provider = (value) => (values = null, provider.value = value, notify(), provider);
provider.close = () => {
provider.closed = true;
providers = providers.filter(p => provider !== p);
values = null;
notify();
};
providers.push(provider);
if (initial !== undefined) provider(initial);
return provider;
}

service.newConsumer = function newConsumer(listener) {
const consumer = () => service();
consumer.listener = listener;
consumer.close = () => {
consumer.closed = true;
consumers = consumers.filter(c => consumer !== c);
};
consumers.push(consumer);
consumer.listener && consumer.listener(service());
return consumer;
}

return service;
}
Insert cell
function newServices({ services = {}, index = {} } = {}) {
function getService(key, create = true) {
let service = index[key];
if (!service && create) {
service = index[key] = newService();
}
return service;
}
function newConsumer(serviceKey, action) {
const Service = getService(serviceKey);
return Service.newConsumer((list) => action(list));
}
function newProvider(serviceKey, initial) {
const Service = getService(serviceKey);
return Service.newProvider(initial);
}
function close() {
for (const service of Object.values(index)) {
service.close();
}
}
services.index = index;
services.getService = getService;
services.newService = newService;
services.newConsumer = newConsumer;
services.newProvider = newProvider;
services.close = close;
return services;
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more