djledda.de main
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 

75 linhas
1.6 KiB

  1. const contextStack: Observer[] = [];
  2. export class Observer<T = unknown> {
  3. private effect: () => T;
  4. dependencies: Set<Observable> = new Set();
  5. constructor(effect: { (): T }) {
  6. this.effect = effect;
  7. this.execute();
  8. }
  9. execute() {
  10. this.cleanup();
  11. contextStack.push(this);
  12. try {
  13. this.effect();
  14. } finally {
  15. contextStack.pop();
  16. }
  17. }
  18. cleanup() {
  19. for (const dep of this.dependencies.values()) {
  20. dep.observers.delete(this);
  21. }
  22. this.dependencies.clear();
  23. }
  24. }
  25. export class Observable<T = unknown> {
  26. private value: T;
  27. observers: Set<Observer> = new Set();
  28. constructor(init: T) {
  29. this.value = init;
  30. }
  31. get() {
  32. const activeObserver = contextStack[contextStack.length - 1];
  33. if (activeObserver) {
  34. this.observers.add(activeObserver);
  35. activeObserver.dependencies.add(this);
  36. }
  37. return this.value;
  38. }
  39. set(next: T) {
  40. this.value = next;
  41. for (const observer of Array.from(this.observers.values())) {
  42. observer.execute();
  43. }
  44. }
  45. }
  46. export class Mapping<T extends unknown> {
  47. private observable: Observable<T>;
  48. private observer: Observer<T>;
  49. constructor(mapping: { (): T }) {
  50. this.observable = new Observable(undefined as T);
  51. this.observer = new Observer(() => {
  52. const result = mapping();
  53. this.observable.set(result);
  54. return result;
  55. });
  56. }
  57. get() {
  58. return this.observable.get();
  59. }
  60. }