import type { Flags } from "./flags.ts" export interface Node { /** * @description 当前节点的上游连接链中的第一个连接。 */ headDepLink?: Link | undefined /** * @description 当前节点的上游连接链中的最后一个连接。 */ tailDepLink?: Link | undefined /** * @description 当前节点的下游连接链中的第一个连接。 */ headSubLink?: Link | undefined /** * @description 当前节点的下游连接链中的最后一个连接。 */ tailSubLink?: Link | undefined /** * @description 当前节点的标记。 */ flags: Flags } /** * @description 连接用于表示某个节点(下游节点)依赖了某个节点(上游节点)。 * * 多个连接连在一起形成连接链,连接链只有两种情况: * * 1. 下游连接链:链中所有连接的上游节点相同,通过该链可以找到该上游节点的所有下游节点。 * 2. 上游连接链:链中所有连接的下游节点相同,通过该链可以找到该下游节点的所有上游节点。 */ export interface Link { /** * @description 连接中的上游节点。 */ dep: Node /** * @description 连接中的上游节点的下游连接链中的上一个连接。(上一个下游连接) */ prevSubLink?: Link | undefined /** * @description 连接中的上游节点的下游连接链中的下一个连接。(下一个下游连接) */ nextSubLink?: Link | undefined /** * @description 连接中的下游节点。 */ sub: Node /** * @description 连接中的下游节点的上游连接链中的上一个连接。(上一个上游连接) */ prevDepLink?: Link | undefined /** * @description 连接中的下游节点的上游连接链中的下一个连接。(下一个上游连接) */ nextDepLink?: Link | undefined } export interface CreateReactiveSystemOptions { /** * @description 当节点的上游节点发生变化时此回调会执行。 */ onDepChanged?: (sub: Node) => void /** * @description 当节点的下游节点发生变化时此回调会执行。 */ onSubChanged?: (dep: Node) => void /** * @description 当节点拥有第一个上游节点时此回调会执行。 */ onHasDep?: (sub: Node, dep: Node) => void /** * @description 当节点不再拥有任何上游节点时此回调会执行。 */ onNoDep?: (sub: Node, dep: Node) => void /** * @description 当节点拥有第一个下游节点时此回调会执行。 */ onHasSub?: (dep: Node, sub: Node) => void /** * @description 当节点不再拥有任何下游节点时此回调会执行。 */ onNoSub?: (dep: Node, sub: Node) => void /** * @description 当节点的值需要更新时此回调会执行,返回值表示更新前后值是否变化。 */ update(sub: Node): boolean /** * @description 当节点的上游节点的值发生变化后此回调会执行。 * * 注意:只有包含 Watching 标记的节点会触发此方法。 */ notify(node: Node): void } export interface ReactiveSystem { /** * @description 获取节点的上游连接。 */ getDepLinksOfNode(node: Node): Link[] /** * @description 获取节点的下游连接。 */ getSubLinksOfNode(node: Node): Link[] /** * @description 获取节点的上游节点。 */ getDepsOfNode(node: Node): Node[] /** * @description 获取节点的下游节点。 */ getSubsOfNode(node: Node): Node[] /** * @description 判断连接是否是节点的上游连接。 */ isDepLinkOfNode(link: Link, node: Node): boolean /** * @description 判断连接是否是节点的下游连接。 */ isSubLinkOfNode(link: Link, node: Node): boolean /** * @description 判断节点是否是目标节点的上游节点。 */ isDepOfNode(node: Node, targetNode: Node): boolean /** * @description 判断节点是否是目标节点的下游节点。 */ isSubOfNode(node: Node, targetNode: Node): boolean /** * @description 获取两个节点之间的连接(从上游节点的下游连接链中查找)。 */ getLinkBetweenFromDep(dep: Node, sub: Node): Link | undefined /** * @description 获取两个节点之间的连接(从下游节点的上游连接链中查找)。 */ getLinkBetweenFromSub(dep: Node, sub: Node): Link | undefined /** * @description 判断两个节点之间是否存在连接(从上游节点的下游连接链中查找)。 */ hasLinkBetweenFromDep(dep: Node, sub: Node): boolean /** * @description 判断两个节点之间是否存在连接(从下游节点的上游连接链中查找)。 */ hasLinkBetweenFromSub(dep: Node, sub: Node): boolean /** * @description 为两个节点建立连接。 */ addLinkBetween(dep: Node, sub: Node): Link /** * @description 为两个节点移除连接(从上游节点的下游连接链中查找)。 */ removeLinkBetweenFromDep(dep: Node, sub: Node): void /** * @description 为两个节点移除连接(从下游节点的上游连接链中查找)。 */ removeLinkBetweenFromSub(dep: Node, sub: Node): void /** * @description 移除连接。 */ removeLink(link: Link): void /** * @description 为节点移除所有上游连接。 */ removeAllDepLinksOfNode(node: Node): Node[] /** * @description 为节点移除所有下游连接。 */ removeAllSubLinksOfNode(node: Node): Node[] /** * @description 获取当前正在进行依赖收集的节点。 */ getActiveNodeAsSub(): Node | undefined /** * @description 设置当前正在进行依赖收集的节点。 */ setActiveNodeAsSub(nodeAsSub: Node | undefined): Node | undefined /** * @description 设置当前正在进行依赖收集的节点为空。 */ setNoActiveNodeAsSub(): undefined /** * @description 重置当前正在进行依赖收集的节点。 */ resetActiveNodeAsSub(): Node | undefined /** * @description 将指定节点作为当前正在进行依赖收集的节点执行指定函数。 */ withActiveNodeAsSub(nodeAsSub: Node | undefined, fn: () => T): T /** * @description 以无当前正在进行依赖收集的节点的状态执行指定函数。 */ withoutActiveNodeAsSub(fn: () => T): T /** * @description 断言当前没有正在进行依赖收集的节点。 */ assertWithoutActiveNodeAsSub(): void /** * @description 开始对节点(作为下游节点)进行依赖收集。 */ startTracking(node: Node): void /** * @description 结束对节点(作为下游节点)进行依赖收集。 */ endTracking(node: Node): void /** * @description 对节点(作为下游节点)进行依赖收集。 */ withTracking(node: Node, fn: () => T): T /** * @description 以无当前正在进行依赖收集的节点的状态执行指定函数。 */ withoutTracking(fn: () => T): T /** * @description 断言当前没有正在进行依赖收集的节点。 */ assertWithoutTracking(): void /** * @description 为两个节点建立连接(依赖收集优化版)。 */ addLinkBetweenOptimizedForTracking(dep: Node, sub: Node): Link /** * @description 将节点作为当前正在进行依赖收集的节点的上游节点。 */ track(node: Node): void /** * @description 将节点作为当前正在进行依赖收集的节点的上游节点。 */ trackNearestMutableOrWatching(node: Node): void /** * @description 当节点的值发生变化后,调用此方法更新直接下游节点的标记。 */ shallowPropagate(node: Node): void /** * @description 当节点的值发生变化后,调用此方法更新所有下游节点的标记。 */ deeeeepPropagate(node: Node): void /** * @description 解决节点的 Pending 标记。 */ resolvePending(node: Node): void } export const createReactiveSystem = (options: CreateReactiveSystemOptions): ReactiveSystem => { const { onDepChanged, onSubChanged, onHasDep, onNoDep, onHasSub, onNoSub, update, notify } = options /** * @description 获取目标节点的所有上游连接。 * * 依赖收集过程中会尝试复用现存连接,该机制会导致在未完全完成依赖收集前,连接链中可能出现 * 未经验证的连接。此方法只会返回经过验证的连接。 */ const getDepLinksOfNode = (node: Node): Link[] => { const depLinks: Link[] = [] let currentDepLink = node.headDepLink const tailDepLink = node.tailDepLink while (currentDepLink !== undefined) { depLinks.push(currentDepLink) const isValidLastDepLink = currentDepLink === tailDepLink if (isValidLastDepLink === true) { break } else { currentDepLink = currentDepLink.nextDepLink } } return depLinks } /** * @description 获取目标节点的所有下游连接。 * * 依赖收集过程中会尝试复用现存连接,该机制会导致在未完全完成依赖收集前,连接链中可能出现 * 未经验证的连接。此方法只会返回经过验证的连接。 */ const getSubLinksOfNode = (node: Node): Link[] => { const subLinks: Link[] = [] let currentSubLink = node.headSubLink const tailSubLink = node.tailSubLink while (currentSubLink !== undefined) { subLinks.push(currentSubLink) const isValidLastSubLink = currentSubLink === tailSubLink if (isValidLastSubLink === true) { break } else { currentSubLink = currentSubLink.nextSubLink } } return subLinks } const getDepsOfNode = (node: Node): Node[] => { const depLinks = getDepLinksOfNode(node) const deps = depLinks.map((link) => link.dep) return deps } const getSubsOfNode = (node: Node): Node[] => { const subLinks = getSubLinksOfNode(node) const subs = subLinks.map((link) => link.sub) return subs } const isDepLinkOfNode = (link: Link, node: Node): boolean => { let currentDepLink = node.headDepLink const tailDepLink = node.tailDepLink while (currentDepLink !== undefined) { if (currentDepLink === link) { return true } const isValidLastDepLink = currentDepLink === tailDepLink if (isValidLastDepLink === true) { break } else { currentDepLink = currentDepLink.nextDepLink } } return false } const isSubLinkOfNode = (link: Link, node: Node): boolean => { let currentSubLink = node.headSubLink const tailSubLink = node.tailSubLink while (currentSubLink !== undefined) { if (currentSubLink === link) { return true } const isValidLastSubLink = currentSubLink === tailSubLink if (isValidLastSubLink === true) { break } else { currentSubLink = currentSubLink.nextSubLink } } return false } const isDepOfNode = (node: Node, targetNode: Node): boolean => { let currentDepLink = targetNode.headDepLink const tailDepLink = targetNode.tailDepLink while (currentDepLink !== undefined) { if (currentDepLink.dep === node) { return true } const isValidLastDepLink = currentDepLink === tailDepLink if (isValidLastDepLink === true) { break } else { currentDepLink = currentDepLink.nextDepLink } } return false } const isSubOfNode = (node: Node, targetNode: Node): boolean => { let currentSubLink = targetNode.headSubLink const tailSubLink = targetNode.tailSubLink while (currentSubLink !== undefined) { if (currentSubLink.sub === node) { return true } const isValidLastSubLink = currentSubLink === tailSubLink if (isValidLastSubLink === true) { break } else { currentSubLink = currentSubLink.nextSubLink } } return false } const getLinkBetweenFromDep = (dep: Node, sub: Node): Link | undefined => { let currentSubLink = dep.headSubLink const tailSubLink = dep.tailSubLink while (currentSubLink !== undefined) { if (currentSubLink.sub === sub) { return currentSubLink } const isValidLastSubLink = currentSubLink === tailSubLink if (isValidLastSubLink === true) { break } else { currentSubLink = currentSubLink.nextSubLink } } return undefined } const getLinkBetweenFromSub = (dep: Node, sub: Node): Link | undefined => { let currentDepLink = sub.headDepLink const tailDepLink = sub.tailDepLink while (currentDepLink !== undefined) { if (currentDepLink.dep === dep) { return currentDepLink } const isValidLastDepLink = currentDepLink === tailDepLink if (isValidLastDepLink === true) { break } else { currentDepLink = currentDepLink.nextDepLink } } return undefined } const hasLinkBetweenFromDep = (dep: Node, sub: Node): boolean => { const link = getLinkBetweenFromDep(dep, sub) return link !== undefined } const hasLinkBetweenFromSub = (dep: Node, sub: Node): boolean => { const link = getLinkBetweenFromSub(dep, sub) return link !== undefined } const addLinkBetween = (dep: Node, sub: Node): Link => { /** * @description 检查是否存在重复连接。 */ const existLink = getLinkBetweenFromSub(dep, sub) if (existLink !== undefined) { return existLink } /** * @description 建立新连接。 */ const newLink: Link = { dep, prevSubLink: undefined, nextSubLink: undefined, sub, prevDepLink: undefined, nextDepLink: undefined, } const tailDepLinkOfSub = sub.tailDepLink if (tailDepLinkOfSub !== undefined) { tailDepLinkOfSub.nextDepLink = newLink newLink.prevDepLink = tailDepLinkOfSub } else { sub.headDepLink = newLink } sub.tailDepLink = newLink const tailSubLinkOfDep = dep.tailSubLink if (tailSubLinkOfDep !== undefined) { tailSubLinkOfDep.nextSubLink = newLink newLink.prevSubLink = tailSubLinkOfDep } else { dep.headSubLink = newLink } dep.tailSubLink = newLink /** * @description 连接全部更新完成之后,触发回调,优先通知上游节点。 */ onSubChanged?.(dep) const isFirstSub = tailSubLinkOfDep === undefined if (isFirstSub === true) { onHasSub?.(dep, sub) } onDepChanged?.(sub) const isFirstDep = tailDepLinkOfSub === undefined if (isFirstDep === true) { onHasDep?.(sub, dep) } return newLink } const removeLinkBetweenFromDep = (dep: Node, sub: Node): void => { const linkFromDep = getLinkBetweenFromDep(dep, sub) if (linkFromDep !== undefined) { removeLink(linkFromDep) } } const removeLinkBetweenFromSub = (dep: Node, sub: Node): void => { const linkFromSub = getLinkBetweenFromSub(dep, sub) if (linkFromSub !== undefined) { removeLink(linkFromSub) } } const removeLink = (link: Link): void => { const prevDepLink = link.prevDepLink const dep = link.dep const nextDepLink = link.nextDepLink const prevSubLink = link.prevSubLink const sub = link.sub const nextSubLink = link.nextSubLink /** * @description 处理上游连接链。 */ if (nextDepLink !== undefined) { // 如果当前连接的下一个连接存在,则将当前连接的下一个连接的上一个连接指向当前连接的上一个连接 nextDepLink.prevDepLink = prevDepLink } else { // 如果当前连接的下一个连接不存在,则将当前连接的上一个连接作为最后一个连接 sub.tailDepLink = prevDepLink } if (prevDepLink !== undefined) { // 如果当前连接的上一个连接存在,则将当前连接的上一个连接的下一个连接指向当前连接的下一个连接 prevDepLink.nextDepLink = nextDepLink } else { // 如果当前连接的上一个连接不存在,则将当前连接的下一个连接作为第一个连接 sub.headDepLink = nextDepLink } /** * @description 处理下游连接链。 */ if (nextSubLink !== undefined) { // 如果当前连接的下一个连接存在,则将当前连接的下一个连接的上一个连接指向当前连接的上一个连接 nextSubLink.prevSubLink = prevSubLink } else { // 如果当前连接的下一个连接不存在,则将当前连接的上一个连接作为最后一个连接 dep.tailSubLink = prevSubLink } if (prevSubLink !== undefined) { // 如果当前连接的上一个连接存在,则将当前连接的上一个连接的下一个连接指向当前连接的下一个连接 prevSubLink.nextSubLink = nextSubLink } else { // 如果当前连接的上一个连接不存在,则将当前连接的下一个连接作为第一个连接 dep.headSubLink = nextSubLink } /** * @description 连接全部更新完成之后,触发回调,优先通知上游节点。 */ onSubChanged?.(dep) if (dep.headSubLink === undefined && dep.tailSubLink === undefined) { onNoSub?.(dep, sub) } onDepChanged?.(sub) if (sub.headDepLink === undefined && sub.tailDepLink === undefined) { onNoDep?.(sub, dep) } /** * @description 彻底断引用,防止内存泄漏。 */ link.prevDepLink = undefined link.dep = undefined as unknown as Node // type cast link.nextDepLink = undefined link.prevSubLink = undefined link.sub = undefined as unknown as Node // type cast link.nextSubLink = undefined } const removeAllDepLinksOfNode = (node: Node): Node[] => { const depNodes = [] let currentDepLink = node.headDepLink while (currentDepLink !== undefined) { depNodes.push(currentDepLink.dep) const nextDepLink = currentDepLink.nextDepLink removeLink(currentDepLink) currentDepLink = nextDepLink } return depNodes } const removeAllSubLinksOfNode = (node: Node): Node[] => { const subNodes = [] let currentSubLink = node.headSubLink while (currentSubLink !== undefined) { subNodes.push(currentSubLink.sub) const nextSubLink = currentSubLink.nextSubLink removeLink(currentSubLink) currentSubLink = nextSubLink } return subNodes } const prevActiveNodeAsSubStack: Array = [] let activeNodeAsSub: Node | undefined = undefined const getActiveNodeAsSub = (): Node | undefined => { return activeNodeAsSub } const setActiveNodeAsSub = (nodeAsSub: Node | undefined): Node | undefined => { prevActiveNodeAsSubStack.push(activeNodeAsSub) activeNodeAsSub = nodeAsSub return activeNodeAsSub } const setNoActiveNodeAsSub = (): undefined => { return setActiveNodeAsSub(undefined) as undefined } const resetActiveNodeAsSub = (): Node | undefined => { activeNodeAsSub = prevActiveNodeAsSubStack.pop() return activeNodeAsSub } const withActiveNodeAsSub = (nodeAsSub: Node | undefined, fn: () => T): T => { setActiveNodeAsSub(nodeAsSub) try { return fn() } finally { resetActiveNodeAsSub() } } const withoutActiveNodeAsSub = (fn: () => T): T => { return withActiveNodeAsSub(undefined, fn) } const assertWithoutActiveNodeAsSub = (): void => { const currentActiveNodeAsSub = getActiveNodeAsSub() if (currentActiveNodeAsSub !== undefined) { throw new Error(`Expected no active node as sub, but got one.`) } } const startTracking = (nodeAsSub: Node): void => { setActiveNodeAsSub(nodeAsSub) const flags = nodeAsSub.flags flags.unsetPending().unsetDirty().setTracking() } const endTracking = (nodeAsSub: Node): void => { const flags = nodeAsSub.flags if (flags.hasTrackingReusing() === true) { const firstRedundantDepLink = nodeAsSub.tailDepLink?.nextDepLink if (firstRedundantDepLink !== undefined) { let toRemove: Link | undefined = firstRedundantDepLink while (toRemove !== undefined) { const nextToRemove: Link | undefined = toRemove.nextDepLink removeLink(toRemove) toRemove = nextToRemove } } } flags.unsetTrackingReusing().unsetTracking() resetActiveNodeAsSub() } const withTracking = (node: Node, fn: () => T): T => { startTracking(node) try { return fn() } finally { endTracking(node) } } const withoutTracking = (fn: () => T): T => { return withoutActiveNodeAsSub(() => { return fn() }) } const assertWithoutTracking = (): void => { try { assertWithoutActiveNodeAsSub() } catch { throw new Error(`Expected no active node as sub for tracking, but got one.`) } } /** * @description 依赖收集的目标是:在完成一次依赖收集之后,对于所有在依赖收集执行过程中被访问过的节点(上游节点), * 都与进行依赖收集的节点(下游节点)建立且仅建立一个连接。 */ const addLinkBetweenOptimizedForTracking = (dep: Node, sub: Node): Link => { let existingDepLinkToCompare: Link | undefined const subFlags = sub.flags if (subFlags.hasTracking() === true && subFlags.hasTrackingReusing() === false) { subFlags.setTrackingReusing() sub.tailDepLink = sub.headDepLink existingDepLinkToCompare = sub.tailDepLink } else { existingDepLinkToCompare = sub.tailDepLink?.nextDepLink } /** * @description 检查是否可以复用现存连接。 */ if (existingDepLinkToCompare !== undefined && existingDepLinkToCompare.dep === dep) { // 如果可以,则复用该连接 sub.tailDepLink = existingDepLinkToCompare // 触发回调 onDepChanged?.(sub) return existingDepLinkToCompare } else { // 否则,建立新连接 const newLink = addLinkBetween(dep, sub) return newLink } } const track = (node: Node): void => { const targetSub = getActiveNodeAsSub() if (targetSub !== undefined) { addLinkBetweenOptimizedForTracking(node, targetSub) } } const trackNearestMutableOrWatching = (node: Node): void => { let targetSub = getActiveNodeAsSub() while (targetSub !== undefined) { const flags = targetSub.flags if (flags.hasMutable() === true || flags.hasWatching() === true) { addLinkBetweenOptimizedForTracking(node, targetSub) break } targetSub = targetSub.headSubLink?.sub } } const shallowPropagate = (node: Node): void => { // 从头到尾遍历目标节点下游连接链中的所有下游节点,更新其标记。 let currentSubLink: Link | undefined = node.headSubLink while (currentSubLink !== undefined) { const sub = currentSubLink.sub const flags = sub.flags let isChangeToDirty = false if (flags.hasPending() === true && flags.hasDirty() === false) { // 如果包含 Pending 标记,且不包含 Dirty 标记,为其添加 Dirty 标记,移除 Pending 标记 flags.setDirty().unsetPending() isChangeToDirty = true } else { // 如果是其它情况,则处理下一个连接 currentSubLink = currentSubLink.nextSubLink continue } if (isChangeToDirty === true) { // 如果检查过程中被标记为 Dirty,则酌情触发 notify 回调 const shouldNotify = flags.hasWatching() === true && flags.hasTracking() === false if (shouldNotify === true) { notify(sub) } } // 当前连接处理完成,处理下一个连接 currentSubLink = currentSubLink.nextSubLink } } interface InternalStack { value: T prev: InternalStack | undefined } const deeeeepPropagate = (node: Node): void => { let currentSubLink = node.headSubLink let nextSubLink = currentSubLink?.nextSubLink let unhandledSubLinkStack: InternalStack | undefined = undefined while (currentSubLink !== undefined) { const sub = currentSubLink.sub let flags = sub.flags let shouldNotify = flags.hasWatching() let shouldDownward = flags.hasMutable() if ( flags.hasTracking() === false && flags.hasDirty() === false && flags.hasPending() === false ) { /** * @description 进入此分支的 flags: * 1. 不包含 Tracking 标记。 * 2. 不包含 Dirty 标记或 Pending 标记。 * * 说明:上游节点的变更首次传递到该节点。 * * 此时,添加 Pending 标记,根据其它标记决定是否需要 Notify,根据其它标记决定是否需要 Downward。 */ flags.setPending() shouldNotify = shouldNotify shouldDownward = shouldDownward } else if (flags.hasTracking() === false) { /** * @description 进入此分支的 flags: * 1. 不包含 Tracking 标记。 * 2. 包含 Dirty 标记或 Pending 标记。 * * 说明:上游节点的变更已经传递到该节点。 * * 此时,什么都不做,不需要修改标记,不需要 Notify,不需要 Downward。 */ flags = flags shouldNotify = false shouldDownward = false } else if (flags.hasDirty() === false && flags.hasPending() === false) { /** * @description 进入此分支的 flags: * 1. 包含 Tracking 标记。 * 2. 不包含 Dirty 标记或 Pending 标记。 * * 说明:上游节点的变更首次传递到该节点,且该节点正在进行依赖收集。 * * 此时,添加 Pending 标记,不需要 Notify,根据其它标记决定是否需要 Downward。 */ flags.setPending() shouldNotify = false shouldDownward = shouldDownward } else { /** * @description 进入此分支的 flags: * 1. 包含 Tracking 标记。 * 2. 包含 Dirty 标记或 Pending 标记。 * * 说明:上游节点的变更已经传递到该节点,且该节点正在进行依赖收集。 * * 此时,不需要修改标记,不需要 Notify,不需要 Downward。 */ flags = flags shouldNotify = false shouldDownward = false } if (shouldNotify === true) { notify(sub) } if (shouldDownward === true) { const headSubLinkOfSub = sub.headSubLink if (headSubLinkOfSub !== undefined) { currentSubLink = headSubLinkOfSub const nextSubLinkOfSub = headSubLinkOfSub.nextSubLink if (nextSubLinkOfSub !== undefined) { unhandledSubLinkStack = { value: nextSubLink, prev: unhandledSubLinkStack } nextSubLink = nextSubLinkOfSub } continue } } currentSubLink = nextSubLink if (currentSubLink !== undefined) { nextSubLink = currentSubLink.nextSubLink continue } if (unhandledSubLinkStack !== undefined) { currentSubLink = unhandledSubLinkStack.value unhandledSubLinkStack = unhandledSubLinkStack.prev if (currentSubLink !== undefined) { nextSubLink = currentSubLink.nextSubLink } } } } const resolvePending = (node: Node): void => { let currentDepLink = node.headDepLink let unhandledDepLinkStack: InternalStack | undefined = undefined while (currentDepLink !== undefined) { const currentSub: Node = currentDepLink.sub const currentDep: Node = currentDepLink.dep const subFlags = currentSub.flags const depFlags = currentDep.flags if (depFlags.hasMutable() === true && depFlags.hasDirty() === true) { /** * @description 当前下游节点不包含 Dirty 标记,当前上游节点包含 Dirty 标记。 * * 更新当前上游节点,若值有变化,则将状态向直接下游节点传播。 */ const valueChanged = update(currentDep) if (valueChanged === true) { shallowPropagate(currentDep) } } else if (depFlags.hasMutable() === true && depFlags.hasPending() === true) { /** * @description 当前下游节点不包含 Dirty 标记,当前上游节点包含 Pending 标记。 * * 继续检查当前上游节点的上游节点。 */ unhandledDepLinkStack = { value: currentDepLink, prev: unhandledDepLinkStack } currentDepLink = currentDep.headDepLink continue } if (subFlags.hasPending() === true) { const nextDepLink = currentDepLink.nextDepLink if (nextDepLink !== undefined) { currentDepLink = nextDepLink continue } } if (unhandledDepLinkStack !== undefined) { currentDepLink = unhandledDepLinkStack.value unhandledDepLinkStack = unhandledDepLinkStack.prev /** * @description 当一个连接先被存起来,后续又被取出来处理时,说明其所有上游节点都已经处理完成, * 因此可以将其 Pending 标记移除。 */ currentDepLink.dep.flags.unsetPending() } else { /** * @description 所有连接都处理完成,可以安全移除当前连接的下游节点的 Pending 标记。 */ currentDepLink.sub.flags.unsetPending() break } } } return { getDepLinksOfNode, getSubLinksOfNode, getDepsOfNode, getSubsOfNode, isDepLinkOfNode, isSubLinkOfNode, isDepOfNode, isSubOfNode, getLinkBetweenFromDep, getLinkBetweenFromSub, hasLinkBetweenFromDep, hasLinkBetweenFromSub, addLinkBetween, removeLinkBetweenFromDep, removeLinkBetweenFromSub, removeLink, removeAllDepLinksOfNode, removeAllSubLinksOfNode, getActiveNodeAsSub, setActiveNodeAsSub, setNoActiveNodeAsSub, resetActiveNodeAsSub, withActiveNodeAsSub, withoutActiveNodeAsSub, assertWithoutActiveNodeAsSub, startTracking, endTracking, withTracking, withoutTracking, assertWithoutTracking, addLinkBetweenOptimizedForTracking, track, trackNearestMutableOrWatching, shallowPropagate, deeeeepPropagate, resolvePending, } }