* Re-evaluate expression with dependency tracking, compare with last * value, and call handler if changed. Returns false if circular * guard tripped (caller should skip this effect). * @returns {boolean} Whether the effect ran successfully
()
| 89 | * @returns {boolean} Whether the effect ran successfully |
| 90 | */ |
| 91 | run() { |
| 92 | this._consecutiveTriggers++; |
| 93 | if (this._consecutiveTriggers > 100) { |
| 94 | console.error( |
| 95 | "Reactivity loop detected: an effect triggered 100 consecutive " + |
| 96 | "times without settling. This usually means an effect is modifying " + |
| 97 | "a variable it also depends on.", |
| 98 | this.element || this |
| 99 | ); |
| 100 | return false; |
| 101 | } |
| 102 | |
| 103 | var reactivity = this._reactivity; |
| 104 | |
| 105 | // Unsubscribe from current deps |
| 106 | reactivity._unsubscribeEffect(this); |
| 107 | |
| 108 | // Re-run expression with tracking |
| 109 | var oldDeps = this.dependencies; |
| 110 | this.dependencies = new Map(); |
| 111 | |
| 112 | var prev = reactivity._currentEffect; |
| 113 | reactivity._currentEffect = this; |
| 114 | var newValue; |
| 115 | try { |
| 116 | newValue = this.expression(); |
| 117 | } catch (e) { |
| 118 | console.error("Error in reactive expression:", e); |
| 119 | // Restore old dependencies on error |
| 120 | this.dependencies = oldDeps; |
| 121 | reactivity._currentEffect = prev; |
| 122 | reactivity._subscribeEffect(this); |
| 123 | return true; |
| 124 | } |
| 125 | reactivity._currentEffect = prev; |
| 126 | |
| 127 | // Subscribe to new deps |
| 128 | reactivity._subscribeEffect(this); |
| 129 | |
| 130 | // Clean up empty subscription entries for deps that were dropped |
| 131 | reactivity._cleanupOrphanedDeps(oldDeps); |
| 132 | |
| 133 | // Compare and fire (Object.is semantics: NaN === NaN, +0 !== -0) |
| 134 | if (!_sameValue(newValue, this._lastValue)) { |
| 135 | this._lastValue = newValue; |
| 136 | try { |
| 137 | this.handler(newValue); |
| 138 | } catch (e) { |
| 139 | console.error("Error in reactive handler:", e); |
| 140 | } |
| 141 | } |
| 142 | return true; |
| 143 | } |
| 144 | |
| 145 | /** Reset circular guard after cascade settles. */ |
| 146 | resetTriggerCount() { |
no test coverage detected