提交学习笔记专用
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.

234 lines
7.1 KiB

  1. export var ReactiveFlags;
  2. (function (ReactiveFlags) {
  3. ReactiveFlags[ReactiveFlags["None"] = 0] = "None";
  4. ReactiveFlags[ReactiveFlags["Mutable"] = 1] = "Mutable";
  5. ReactiveFlags[ReactiveFlags["Watching"] = 2] = "Watching";
  6. ReactiveFlags[ReactiveFlags["RecursedCheck"] = 4] = "RecursedCheck";
  7. ReactiveFlags[ReactiveFlags["Recursed"] = 8] = "Recursed";
  8. ReactiveFlags[ReactiveFlags["Dirty"] = 16] = "Dirty";
  9. ReactiveFlags[ReactiveFlags["Pending"] = 32] = "Pending";
  10. })(ReactiveFlags || (ReactiveFlags = {}));
  11. export function createReactiveSystem({ update, notify, unwatched, }) {
  12. return {
  13. link,
  14. unlink,
  15. propagate,
  16. checkDirty,
  17. shallowPropagate,
  18. };
  19. function link(dep, sub, version) {
  20. const prevDep = sub.depsTail;
  21. if (prevDep !== undefined && prevDep.dep === dep) {
  22. return;
  23. }
  24. const nextDep = prevDep !== undefined ? prevDep.nextDep : sub.deps;
  25. if (nextDep !== undefined && nextDep.dep === dep) {
  26. nextDep.version = version;
  27. sub.depsTail = nextDep;
  28. return;
  29. }
  30. const prevSub = dep.subsTail;
  31. if (prevSub !== undefined && prevSub.version === version && prevSub.sub === sub) {
  32. return;
  33. }
  34. const newLink = sub.depsTail
  35. = dep.subsTail
  36. = {
  37. version,
  38. dep,
  39. sub,
  40. prevDep,
  41. nextDep,
  42. prevSub,
  43. nextSub: undefined,
  44. };
  45. if (nextDep !== undefined) {
  46. nextDep.prevDep = newLink;
  47. }
  48. if (prevDep !== undefined) {
  49. prevDep.nextDep = newLink;
  50. }
  51. else {
  52. sub.deps = newLink;
  53. }
  54. if (prevSub !== undefined) {
  55. prevSub.nextSub = newLink;
  56. }
  57. else {
  58. dep.subs = newLink;
  59. }
  60. }
  61. function unlink(link, sub = link.sub) {
  62. const dep = link.dep;
  63. const prevDep = link.prevDep;
  64. const nextDep = link.nextDep;
  65. const nextSub = link.nextSub;
  66. const prevSub = link.prevSub;
  67. if (nextDep !== undefined) {
  68. nextDep.prevDep = prevDep;
  69. }
  70. else {
  71. sub.depsTail = prevDep;
  72. }
  73. if (prevDep !== undefined) {
  74. prevDep.nextDep = nextDep;
  75. }
  76. else {
  77. sub.deps = nextDep;
  78. }
  79. if (nextSub !== undefined) {
  80. nextSub.prevSub = prevSub;
  81. }
  82. else {
  83. dep.subsTail = prevSub;
  84. }
  85. if (prevSub !== undefined) {
  86. prevSub.nextSub = nextSub;
  87. }
  88. else if ((dep.subs = nextSub) === undefined) {
  89. unwatched(dep);
  90. }
  91. return nextDep;
  92. }
  93. function propagate(link) {
  94. let next = link.nextSub;
  95. let stack;
  96. top: do {
  97. const sub = link.sub;
  98. let flags = sub.flags;
  99. if (!(flags & 60)) {
  100. sub.flags = flags | 32;
  101. }
  102. else if (!(flags & 12)) {
  103. flags = 0;
  104. }
  105. else if (!(flags & 4)) {
  106. sub.flags = (flags & ~8) | 32;
  107. }
  108. else if (!(flags & 48) && isValidLink(link, sub)) {
  109. sub.flags = flags | 40;
  110. flags &= 1;
  111. }
  112. else {
  113. flags = 0;
  114. }
  115. if (flags & 2) {
  116. notify(sub);
  117. }
  118. if (flags & 1) {
  119. const subSubs = sub.subs;
  120. if (subSubs !== undefined) {
  121. const nextSub = (link = subSubs).nextSub;
  122. if (nextSub !== undefined) {
  123. stack = { value: next, prev: stack };
  124. next = nextSub;
  125. }
  126. continue;
  127. }
  128. }
  129. if ((link = next) !== undefined) {
  130. next = link.nextSub;
  131. continue;
  132. }
  133. while (stack !== undefined) {
  134. link = stack.value;
  135. stack = stack.prev;
  136. if (link !== undefined) {
  137. next = link.nextSub;
  138. continue top;
  139. }
  140. }
  141. break;
  142. } while (true);
  143. }
  144. function checkDirty(link, sub) {
  145. let stack;
  146. let checkDepth = 0;
  147. let dirty = false;
  148. top: do {
  149. const dep = link.dep;
  150. const flags = dep.flags;
  151. if (sub.flags & 16) {
  152. dirty = true;
  153. }
  154. else if ((flags & 17) === 17) {
  155. if (update(dep)) {
  156. const subs = dep.subs;
  157. if (subs.nextSub !== undefined) {
  158. shallowPropagate(subs);
  159. }
  160. dirty = true;
  161. }
  162. }
  163. else if ((flags & 33) === 33) {
  164. if (link.nextSub !== undefined || link.prevSub !== undefined) {
  165. stack = { value: link, prev: stack };
  166. }
  167. link = dep.deps;
  168. sub = dep;
  169. ++checkDepth;
  170. continue;
  171. }
  172. if (!dirty) {
  173. const nextDep = link.nextDep;
  174. if (nextDep !== undefined) {
  175. link = nextDep;
  176. continue;
  177. }
  178. }
  179. while (checkDepth--) {
  180. const firstSub = sub.subs;
  181. const hasMultipleSubs = firstSub.nextSub !== undefined;
  182. if (hasMultipleSubs) {
  183. link = stack.value;
  184. stack = stack.prev;
  185. }
  186. else {
  187. link = firstSub;
  188. }
  189. if (dirty) {
  190. if (update(sub)) {
  191. if (hasMultipleSubs) {
  192. shallowPropagate(firstSub);
  193. }
  194. sub = link.sub;
  195. continue;
  196. }
  197. dirty = false;
  198. }
  199. else {
  200. sub.flags &= ~32;
  201. }
  202. sub = link.sub;
  203. const nextDep = link.nextDep;
  204. if (nextDep !== undefined) {
  205. link = nextDep;
  206. continue top;
  207. }
  208. }
  209. return dirty;
  210. } while (true);
  211. }
  212. function shallowPropagate(link) {
  213. do {
  214. const sub = link.sub;
  215. const flags = sub.flags;
  216. if ((flags & 48) === 32) {
  217. sub.flags = flags | 16;
  218. if (flags & 2) {
  219. notify(sub);
  220. }
  221. }
  222. } while ((link = link.nextSub) !== undefined);
  223. }
  224. function isValidLink(checkLink, sub) {
  225. let link = sub.depsTail;
  226. while (link !== undefined) {
  227. if (link === checkLink) {
  228. return true;
  229. }
  230. link = link.prevDep;
  231. }
  232. return false;
  233. }
  234. }