Vue.js設計與實現(xiàn)無限遞歸學習總結
棧溢出
const data = { foo: 1 } const obj = new Proxy(data, {/*...*/}) effect(() => obj.foo = obj.foo + 1)
此項操作會引起棧溢出:
Uncaught RangeError: Maximum call sack size exceeded
在此操作中, 會先讀取obj.foo
的值, 這會觸發(fā)track
操作, 將副作用函數(shù)入棧, 此時有加一并賦值, 此時會觸發(fā)trigger
操作, 將副作用函數(shù)出棧并執(zhí)行, 在這種情況下, 該副作用函數(shù)還在執(zhí)行中, 又開始下一次的執(zhí)行, 導致無限遞歸調(diào)用自己導致棧溢出報錯.
在這個操作中讀取與設置的是同一個副作用函數(shù)activeEffect
, 因此在trigger
要觸發(fā)時添加條件: 如果trigger
觸發(fā)的副作用函數(shù)與當前執(zhí)行的副作用函數(shù)相同, 則不觸發(fā)執(zhí)行:
function trigger (target, key) { const depsMap = bucket.get(target) if (!depsMap) return const effects = depsMap.get(key) const effectsToRun = new Set() effects && effects.forEach(effectFn => { if (effectFn !== activeEffect) { effectsToRun.add(effectFn) } }) effectsToRun.forEach(effectFn => effectFn()) }
目前為止響應式完整代碼
// 儲存副作用函數(shù)的桶 const bucket = new WeakMap() // 用于儲存被注冊的副作用的函數(shù) let activeEffect = undefined // 副作用函數(shù)棧 const effectStack = [] function cleanup (effectFn) { for (let itme of effectFn.deps) { itme.delete(effectFn) } effectFn.deps.length = [] } function effect (fn) { const effectFn = () => { cleanup(effectFn) // 調(diào)用當前的副作用函數(shù)時, 賦值給 全局變量 activeEffect = effectFn // 在調(diào)用副作用函數(shù)之前將該函數(shù)壓入棧 effectStack.push(effectFn) fn()
以上就是Vue.js設計與實現(xiàn)無限遞歸學習總結的詳細內(nèi)容,更多關于Vue.js無限遞歸的資料請關注腳本之家其它相關文章!