提交学习笔记专用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

283 lines
6.7 KiB

  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.getActiveSub = getActiveSub;
  4. exports.setActiveSub = setActiveSub;
  5. exports.getBatchDepth = getBatchDepth;
  6. exports.startBatch = startBatch;
  7. exports.endBatch = endBatch;
  8. exports.isSignal = isSignal;
  9. exports.isComputed = isComputed;
  10. exports.isEffect = isEffect;
  11. exports.isEffectScope = isEffectScope;
  12. exports.signal = signal;
  13. exports.computed = computed;
  14. exports.effect = effect;
  15. exports.effectScope = effectScope;
  16. const system_js_1 = require("./system.cjs");
  17. let cycle = 0;
  18. let batchDepth = 0;
  19. let notifyIndex = 0;
  20. let queuedLength = 0;
  21. let activeSub;
  22. const queued = [];
  23. const { link, unlink, propagate, checkDirty, shallowPropagate, } = (0, system_js_1.createReactiveSystem)({
  24. update(node) {
  25. if (node.depsTail !== undefined) {
  26. return updateComputed(node);
  27. }
  28. else {
  29. return updateSignal(node);
  30. }
  31. },
  32. notify(effect) {
  33. let insertIndex = queuedLength;
  34. let firstInsertedIndex = insertIndex;
  35. do {
  36. effect.flags &= ~2;
  37. queued[insertIndex++] = effect;
  38. effect = effect.subs?.sub;
  39. if (effect === undefined || !(effect.flags & 2)) {
  40. break;
  41. }
  42. } while (true);
  43. queuedLength = insertIndex;
  44. while (firstInsertedIndex < --insertIndex) {
  45. const left = queued[firstInsertedIndex];
  46. queued[firstInsertedIndex++] = queued[insertIndex];
  47. queued[insertIndex] = left;
  48. }
  49. },
  50. unwatched(node) {
  51. if (!(node.flags & 1)) {
  52. effectScopeOper.call(node);
  53. }
  54. else if (node.depsTail !== undefined) {
  55. node.depsTail = undefined;
  56. node.flags = 17;
  57. purgeDeps(node);
  58. }
  59. },
  60. });
  61. function getActiveSub() {
  62. return activeSub;
  63. }
  64. function setActiveSub(sub) {
  65. const prevSub = activeSub;
  66. activeSub = sub;
  67. return prevSub;
  68. }
  69. function getBatchDepth() {
  70. return batchDepth;
  71. }
  72. function startBatch() {
  73. ++batchDepth;
  74. }
  75. function endBatch() {
  76. if (!--batchDepth) {
  77. flush();
  78. }
  79. }
  80. function isSignal(fn) {
  81. return fn.name === 'bound ' + signalOper.name;
  82. }
  83. function isComputed(fn) {
  84. return fn.name === 'bound ' + computedOper.name;
  85. }
  86. function isEffect(fn) {
  87. return fn.name === 'bound ' + effectOper.name;
  88. }
  89. function isEffectScope(fn) {
  90. return fn.name === 'bound ' + effectScopeOper.name;
  91. }
  92. function signal(initialValue) {
  93. return signalOper.bind({
  94. currentValue: initialValue,
  95. pendingValue: initialValue,
  96. subs: undefined,
  97. subsTail: undefined,
  98. flags: 1,
  99. });
  100. }
  101. function computed(getter) {
  102. return computedOper.bind({
  103. value: undefined,
  104. subs: undefined,
  105. subsTail: undefined,
  106. deps: undefined,
  107. depsTail: undefined,
  108. flags: 0,
  109. getter: getter,
  110. });
  111. }
  112. function effect(fn) {
  113. const e = {
  114. fn,
  115. subs: undefined,
  116. subsTail: undefined,
  117. deps: undefined,
  118. depsTail: undefined,
  119. flags: 2,
  120. };
  121. const prevSub = setActiveSub(e);
  122. if (prevSub !== undefined) {
  123. link(e, prevSub, 0);
  124. }
  125. try {
  126. e.fn();
  127. }
  128. finally {
  129. activeSub = prevSub;
  130. }
  131. return effectOper.bind(e);
  132. }
  133. function effectScope(fn) {
  134. const e = {
  135. deps: undefined,
  136. depsTail: undefined,
  137. subs: undefined,
  138. subsTail: undefined,
  139. flags: 0,
  140. };
  141. const prevSub = setActiveSub(e);
  142. if (prevSub !== undefined) {
  143. link(e, prevSub, 0);
  144. }
  145. try {
  146. fn();
  147. }
  148. finally {
  149. activeSub = prevSub;
  150. }
  151. return effectScopeOper.bind(e);
  152. }
  153. function updateComputed(c) {
  154. ++cycle;
  155. c.depsTail = undefined;
  156. c.flags = 5;
  157. const prevSub = setActiveSub(c);
  158. try {
  159. const oldValue = c.value;
  160. return oldValue !== (c.value = c.getter(oldValue));
  161. }
  162. finally {
  163. activeSub = prevSub;
  164. c.flags &= ~4;
  165. purgeDeps(c);
  166. }
  167. }
  168. function updateSignal(s) {
  169. s.flags = 1;
  170. return s.currentValue !== (s.currentValue = s.pendingValue);
  171. }
  172. function run(e) {
  173. const flags = e.flags;
  174. if (flags & 16
  175. || (flags & 32
  176. && checkDirty(e.deps, e))) {
  177. ++cycle;
  178. e.depsTail = undefined;
  179. e.flags = 6;
  180. const prevSub = setActiveSub(e);
  181. try {
  182. e.fn();
  183. }
  184. finally {
  185. activeSub = prevSub;
  186. e.flags &= ~4;
  187. purgeDeps(e);
  188. }
  189. }
  190. else {
  191. e.flags = 2;
  192. }
  193. }
  194. function flush() {
  195. while (notifyIndex < queuedLength) {
  196. const effect = queued[notifyIndex];
  197. queued[notifyIndex++] = undefined;
  198. run(effect);
  199. }
  200. notifyIndex = 0;
  201. queuedLength = 0;
  202. }
  203. function computedOper() {
  204. const flags = this.flags;
  205. if (flags & 16
  206. || (flags & 32
  207. && (checkDirty(this.deps, this)
  208. || (this.flags = flags & ~32, false)))) {
  209. if (updateComputed(this)) {
  210. const subs = this.subs;
  211. if (subs !== undefined) {
  212. shallowPropagate(subs);
  213. }
  214. }
  215. }
  216. else if (!flags) {
  217. this.flags = 1;
  218. const prevSub = setActiveSub(this);
  219. try {
  220. this.value = this.getter();
  221. }
  222. finally {
  223. activeSub = prevSub;
  224. }
  225. }
  226. const sub = activeSub;
  227. if (sub !== undefined) {
  228. link(this, sub, cycle);
  229. }
  230. return this.value;
  231. }
  232. function signalOper(...value) {
  233. if (value.length) {
  234. if (this.pendingValue !== (this.pendingValue = value[0])) {
  235. this.flags = 17;
  236. const subs = this.subs;
  237. if (subs !== undefined) {
  238. propagate(subs);
  239. if (!batchDepth) {
  240. flush();
  241. }
  242. }
  243. }
  244. }
  245. else {
  246. if (this.flags & 16) {
  247. if (updateSignal(this)) {
  248. const subs = this.subs;
  249. if (subs !== undefined) {
  250. shallowPropagate(subs);
  251. }
  252. }
  253. }
  254. let sub = activeSub;
  255. while (sub !== undefined) {
  256. if (sub.flags & 3) {
  257. link(this, sub, cycle);
  258. break;
  259. }
  260. sub = sub.subs?.sub;
  261. }
  262. return this.currentValue;
  263. }
  264. }
  265. function effectOper() {
  266. effectScopeOper.call(this);
  267. }
  268. function effectScopeOper() {
  269. this.depsTail = undefined;
  270. this.flags = 0;
  271. purgeDeps(this);
  272. const sub = this.subs;
  273. if (sub !== undefined) {
  274. unlink(sub);
  275. }
  276. }
  277. function purgeDeps(sub) {
  278. const depsTail = sub.depsTail;
  279. let dep = depsTail !== undefined ? depsTail.nextDep : sub.deps;
  280. while (dep !== undefined) {
  281. dep = unlink(dep, sub);
  282. }
  283. }