UNPKG

scrivito

Version:

Scrivito is a professional, yet easy to use SaaS Enterprise Content Management Service, built for digital agencies and medium to large businesses. It is completely maintenance-free, cost-effective, and has unprecedented performance and security.

95 lines (78 loc) 2.74 kB
import { ContextContainer, collectAndSchedule, nextTick, } from 'scrivito_sdk/common'; import { StateSubscriber } from 'scrivito_sdk/state'; import { withFrozenState } from 'scrivito_sdk/state/frozen'; import { SubscriberSet } from 'scrivito_sdk/state/subscriber_set'; const syncSubscribers = new SubscriberSet(); const asyncSubscribers = new SubscriberSet(); /** create a new StateSubscriber that will invoke listeners _asynchronously_, * when changes happen to subscribed state. */ export function createAsyncSubscriber(listener: () => void): StateSubscriber { return asyncSubscribers.create(listener); } /** create a new StateSubscriber that will invoke listeners _synchronously_, * when changes happen to subscribed state. * You can pass in a `rank`, which influences the order, in which listeners are notified: * listeners with lower rank are notified before listeners with higher rank. */ export function createSyncSubscriber( listener: () => void, rank = 0 ): StateSubscriber { return syncSubscribers.create(listener, rank); } const batchUpdates = new ContextContainer<boolean>(); let notifiedDuringBatchUpdates = false; export function withBatchedUpdates(fn: () => void) { try { batchUpdates.runWith(true, fn); } finally { if (!batchUpdates.current() && notifiedDuringBatchUpdates) { notifiedDuringBatchUpdates = false; notifySubscribers(); } } } let notificationCounter = 0; // for test purposes export function createNotificationCounter(): () => number { const startedAt = notificationCounter; return () => notificationCounter - startedAt; } // for test purposes only export function listenerCount(): number { return syncSubscribers.count() + asyncSubscribers.count(); } export function notifySubscribers() { if (batchUpdates.current()) { notifiedDuringBatchUpdates = true; return; } notificationCounter++; // listeners should not change state, at least not synchronously, // since that would create chaos, e.g. race condition between listeners, // breaking the one-way-flow of a reactive application, stack overflow etc. // you may use nextTick to make a state change asynchronously, though. withFrozenState({ contextName: 'state listeners' }, () => { notifySyncSubscribers(); notifyAsyncSubscribers(); }); } export function resetSubscribers() { syncSubscribers.reset(); asyncSubscribers.reset(); } function notifySyncSubscribers() { syncSubscribers.forEach((subscriber) => { if (subscriber.hasChanges()) subscriber.notify(); }); } const notifyAsyncSubscribers = collectAndSchedule(nextTick, () => asyncSubscribers.forEach((subscriber) => { if (subscriber.hasChanges()) subscriber.scheduleNotify(); }) );