-import { observable, autorun, unwrap, isObservable } from '../../src'
+import { observable, effect, unwrap, isObservable } from '../../src'
describe('observer/collections', () => {
describe('Map', () => {
it('should observe mutations', () => {
let dummy
const map = observable(new Map())
- autorun(() => {
+ effect(() => {
dummy = map.get('key')
})
it('should observe size mutations', () => {
let dummy
const map = observable(new Map())
- autorun(() => (dummy = map.size))
+ effect(() => (dummy = map.size))
expect(dummy).toBe(0)
map.set('key1', 'value')
it('should observe for of iteration', () => {
let dummy
const map = observable(new Map())
- autorun(() => {
+ effect(() => {
dummy = 0
// eslint-disable-next-line no-unused-vars
for (let [key, num] of map) {
it('should observe forEach iteration', () => {
let dummy: any
const map = observable(new Map())
- autorun(() => {
+ effect(() => {
dummy = 0
map.forEach((num: any) => (dummy += num))
})
it('should observe keys iteration', () => {
let dummy
const map = observable(new Map())
- autorun(() => {
+ effect(() => {
dummy = 0
for (let key of map.keys()) {
dummy += key
it('should observe values iteration', () => {
let dummy
const map = observable(new Map())
- autorun(() => {
+ effect(() => {
dummy = 0
for (let num of map.values()) {
dummy += num
it('should observe entries iteration', () => {
let dummy
const map = observable(new Map())
- autorun(() => {
+ effect(() => {
dummy = 0
// eslint-disable-next-line no-unused-vars
for (let [key, num] of map.entries()) {
it('should be triggered by clearing', () => {
let dummy
const map = observable(new Map())
- autorun(() => (dummy = map.get('key')))
+ effect(() => (dummy = map.get('key')))
expect(dummy).toBe(undefined)
map.set('key', 3)
it('should not observe custom property mutations', () => {
let dummy
const map: any = observable(new Map())
- autorun(() => (dummy = map.customProp))
+ effect(() => (dummy = map.customProp))
expect(dummy).toBe(undefined)
map.customProp = 'Hello World'
let dummy
const map = observable(new Map())
const mapSpy = jest.fn(() => (dummy = map.get('key')))
- autorun(mapSpy)
+ effect(mapSpy)
expect(dummy).toBe(undefined)
expect(mapSpy).toHaveBeenCalledTimes(1)
it('should not observe raw data', () => {
let dummy
const map = observable(new Map())
- autorun(() => (dummy = unwrap(map).get('key')))
+ effect(() => (dummy = unwrap(map).get('key')))
expect(dummy).toBe(undefined)
map.set('key', 'Hello')
const observed = observable(new Map())
observed.set('key', { a: 1 })
let dummy
- autorun(() => {
+ effect(() => {
dummy = observed.get('key').a
})
observed.get('key').a = 2
it('should observe nested values in iterations (forEach)', () => {
const map = observable(new Map([[1, { foo: 1 }]]))
let dummy: any
- autorun(() => {
+ effect(() => {
dummy = 0
map.forEach(value => {
expect(isObservable(value)).toBe(true)
it('should observe nested values in iterations (values)', () => {
const map = observable(new Map([[1, { foo: 1 }]]))
let dummy: any
- autorun(() => {
+ effect(() => {
dummy = 0
for (const value of map.values()) {
expect(isObservable(value)).toBe(true)
const key = {}
const map = observable(new Map([[key, { foo: 1 }]]))
let dummy: any
- autorun(() => {
+ effect(() => {
dummy = 0
for (const [key, value] of map.entries()) {
key
const key = {}
const map = observable(new Map([[key, { foo: 1 }]]))
let dummy: any
- autorun(() => {
+ effect(() => {
dummy = 0
for (const [key, value] of map) {
key
-import { observable, autorun, isObservable, unwrap } from '../../src'
+import { observable, effect, isObservable, unwrap } from '../../src'
describe('observer/collections', () => {
describe('Set', () => {
it('should observe mutations', () => {
let dummy
const set = observable(new Set())
- autorun(() => (dummy = set.has('value')))
+ effect(() => (dummy = set.has('value')))
expect(dummy).toBe(false)
set.add('value')
it('should observe for of iteration', () => {
let dummy
const set = observable(new Set())
- autorun(() => {
+ effect(() => {
dummy = 0
for (let num of set) {
dummy += num
it('should observe forEach iteration', () => {
let dummy: any
const set = observable(new Set())
- autorun(() => {
+ effect(() => {
dummy = 0
set.forEach(num => (dummy += num))
})
it('should observe values iteration', () => {
let dummy
const set = observable(new Set())
- autorun(() => {
+ effect(() => {
dummy = 0
for (let num of set.values()) {
dummy += num
it('should observe keys iteration', () => {
let dummy
const set = observable(new Set())
- autorun(() => {
+ effect(() => {
dummy = 0
for (let num of set.keys()) {
dummy += num
it('should observe entries iteration', () => {
let dummy
const set = observable(new Set())
- autorun(() => {
+ effect(() => {
dummy = 0
// eslint-disable-next-line no-unused-vars
for (let [key, num] of set.entries()) {
it('should be triggered by clearing', () => {
let dummy
const set = observable(new Set())
- autorun(() => (dummy = set.has('key')))
+ effect(() => (dummy = set.has('key')))
expect(dummy).toBe(false)
set.add('key')
it('should not observe custom property mutations', () => {
let dummy
const set: any = observable(new Set())
- autorun(() => (dummy = set.customProp))
+ effect(() => (dummy = set.customProp))
expect(dummy).toBe(undefined)
set.customProp = 'Hello World'
it('should observe size mutations', () => {
let dummy
const set = observable(new Set())
- autorun(() => (dummy = set.size))
+ effect(() => (dummy = set.size))
expect(dummy).toBe(0)
set.add('value')
let dummy
const set = observable(new Set())
const setSpy = jest.fn(() => (dummy = set.has('value')))
- autorun(setSpy)
+ effect(setSpy)
expect(dummy).toBe(false)
expect(setSpy).toHaveBeenCalledTimes(1)
it('should not observe raw data', () => {
let dummy
const set = observable(new Set())
- autorun(() => (dummy = unwrap(set).has('value')))
+ effect(() => (dummy = unwrap(set).has('value')))
expect(dummy).toBe(false)
set.add('value')
it('should not observe raw iterations', () => {
let dummy = 0
const set = observable(new Set())
- autorun(() => {
+ effect(() => {
dummy = 0
for (let [num] of unwrap(set).entries()) {
dummy += num
it('should not be triggered by raw mutations', () => {
let dummy
const set = observable(new Set())
- autorun(() => (dummy = set.has('value')))
+ effect(() => (dummy = set.has('value')))
expect(dummy).toBe(false)
unwrap(set).add('value')
it('should not observe raw size mutations', () => {
let dummy
const set = observable(new Set())
- autorun(() => (dummy = unwrap(set).size))
+ effect(() => (dummy = unwrap(set).size))
expect(dummy).toBe(0)
set.add('value')
it('should not be triggered by raw size mutations', () => {
let dummy
const set = observable(new Set())
- autorun(() => (dummy = set.size))
+ effect(() => (dummy = set.size))
expect(dummy).toBe(0)
unwrap(set).add('value')
const key = {}
const set = observable(new Set())
const setSpy = jest.fn(() => (dummy = set.has(key)))
- autorun(setSpy)
+ effect(setSpy)
expect(dummy).toBe(false)
expect(setSpy).toHaveBeenCalledTimes(1)
it('should observe nested values in iterations (forEach)', () => {
const set = observable(new Set([{ foo: 1 }]))
let dummy: any
- autorun(() => {
+ effect(() => {
dummy = 0
set.forEach(value => {
expect(isObservable(value)).toBe(true)
it('should observe nested values in iterations (values)', () => {
const set = observable(new Set([{ foo: 1 }]))
let dummy: any
- autorun(() => {
+ effect(() => {
dummy = 0
for (const value of set.values()) {
expect(isObservable(value)).toBe(true)
it('should observe nested values in iterations (entries)', () => {
const set = observable(new Set([{ foo: 1 }]))
let dummy: any
- autorun(() => {
+ effect(() => {
dummy = 0
for (const [key, value] of set.entries()) {
expect(isObservable(key)).toBe(true)
it('should observe nested values in iterations (for...of)', () => {
const set = observable(new Set([{ foo: 1 }]))
let dummy: any
- autorun(() => {
+ effect(() => {
dummy = 0
for (const value of set) {
expect(isObservable(value)).toBe(true)
-import { observable, autorun, unwrap, isObservable } from '../../src'
+import { observable, effect, unwrap, isObservable } from '../../src'
describe('observer/collections', () => {
describe('WeakMap', () => {
let dummy
const key = {}
const map = observable(new WeakMap())
- autorun(() => {
+ effect(() => {
dummy = map.get(key)
})
it('should not observe custom property mutations', () => {
let dummy
const map: any = observable(new WeakMap())
- autorun(() => (dummy = map.customProp))
+ effect(() => (dummy = map.customProp))
expect(dummy).toBe(undefined)
map.customProp = 'Hello World'
const key = {}
const map = observable(new WeakMap())
const mapSpy = jest.fn(() => (dummy = map.get(key)))
- autorun(mapSpy)
+ effect(mapSpy)
expect(dummy).toBe(undefined)
expect(mapSpy).toHaveBeenCalledTimes(1)
let dummy
const key = {}
const map = observable(new WeakMap())
- autorun(() => (dummy = unwrap(map).get(key)))
+ effect(() => (dummy = unwrap(map).get(key)))
expect(dummy).toBe(undefined)
map.set(key, 'Hello')
const key = {}
observed.set(key, { a: 1 })
let dummy
- autorun(() => {
+ effect(() => {
dummy = observed.get(key).a
})
observed.get(key).a = 2
-import { observable, isObservable, autorun, unwrap } from '../../src'
+import { observable, isObservable, effect, unwrap } from '../../src'
describe('observer/collections', () => {
describe('WeakSet', () => {
let dummy
const value = {}
const set = observable(new WeakSet())
- autorun(() => (dummy = set.has(value)))
+ effect(() => (dummy = set.has(value)))
expect(dummy).toBe(false)
set.add(value)
it('should not observe custom property mutations', () => {
let dummy
const set: any = observable(new WeakSet())
- autorun(() => (dummy = set.customProp))
+ effect(() => (dummy = set.customProp))
expect(dummy).toBe(undefined)
set.customProp = 'Hello World'
const value = {}
const set = observable(new WeakSet())
const setSpy = jest.fn(() => (dummy = set.has(value)))
- autorun(setSpy)
+ effect(setSpy)
expect(dummy).toBe(false)
expect(setSpy).toHaveBeenCalledTimes(1)
const value = {}
let dummy
const set = observable(new WeakSet())
- autorun(() => (dummy = unwrap(set).has(value)))
+ effect(() => (dummy = unwrap(set).has(value)))
expect(dummy).toBe(false)
set.add(value)
const value = {}
let dummy
const set = observable(new WeakSet())
- autorun(() => (dummy = set.has(value)))
+ effect(() => (dummy = set.has(value)))
expect(dummy).toBe(false)
unwrap(set).add(value)
-import { computed, observable, autorun, stop } from '../src'
+import { computed, observable, effect, stop } from '../src'
describe('observer/computed', () => {
it('should return updated value', () => {
expect(callArg).toBe(ctx)
})
- it('should trigger autorun', () => {
+ it('should trigger effect', () => {
const value: any = observable({})
const cValue = computed(() => value.foo)
let dummy
- autorun(() => {
+ effect(() => {
dummy = cValue()
})
expect(dummy).toBe(undefined)
expect(c1()).toBe(1)
})
- it('should trigger autorun when chained', () => {
+ it('should trigger effect when chained', () => {
const value: any = observable({ foo: 0 })
const getter1 = jest.fn(() => value.foo)
const getter2 = jest.fn(() => {
const c2 = computed(getter2)
let dummy
- autorun(() => {
+ effect(() => {
dummy = c2()
})
expect(dummy).toBe(1)
expect(getter2).toHaveBeenCalledTimes(2)
})
- it('should trigger autorun when chained (mixed invocations)', () => {
+ it('should trigger effect when chained (mixed invocations)', () => {
const value: any = observable({ foo: 0 })
const getter1 = jest.fn(() => value.foo)
const getter2 = jest.fn(() => {
const c2 = computed(getter2)
let dummy
- autorun(() => {
+ effect(() => {
dummy = c1() + c2()
})
expect(dummy).toBe(1)
const value: any = observable({})
const cValue = computed(() => value.foo)
let dummy
- autorun(() => {
+ effect(() => {
dummy = cValue()
})
expect(dummy).toBe(undefined)
value.foo = 1
expect(dummy).toBe(1)
- stop(cValue.runner)
+ stop(cValue.effect)
value.foo = 2
expect(dummy).toBe(1)
})
import {
observable,
- autorun,
+ effect,
stop,
unwrap,
OperationTypes,
DebuggerEvent,
markNonReactive
} from '../src/index'
-import { ITERATE_KEY } from '../src/autorun'
+import { ITERATE_KEY } from '../src/effect'
-describe('observer/autorun', () => {
- it('should run the passed function once (wrapped by a autorun)', () => {
+describe('observer/effect', () => {
+ it('should run the passed function once (wrapped by a effect)', () => {
const fnSpy = jest.fn(() => {})
- autorun(fnSpy)
+ effect(fnSpy)
expect(fnSpy).toHaveBeenCalledTimes(1)
})
it('should observe basic properties', () => {
let dummy
const counter = observable({ num: 0 })
- autorun(() => (dummy = counter.num))
+ effect(() => (dummy = counter.num))
expect(dummy).toBe(0)
counter.num = 7
it('should observe multiple properties', () => {
let dummy
const counter = observable({ num1: 0, num2: 0 })
- autorun(() => (dummy = counter.num1 + counter.num1 + counter.num2))
+ effect(() => (dummy = counter.num1 + counter.num1 + counter.num2))
expect(dummy).toBe(0)
counter.num1 = counter.num2 = 7
expect(dummy).toBe(21)
})
- it('should handle multiple autoruns', () => {
+ it('should handle multiple effects', () => {
let dummy1, dummy2
const counter = observable({ num: 0 })
- autorun(() => (dummy1 = counter.num))
- autorun(() => (dummy2 = counter.num))
+ effect(() => (dummy1 = counter.num))
+ effect(() => (dummy2 = counter.num))
expect(dummy1).toBe(0)
expect(dummy2).toBe(0)
it('should observe nested properties', () => {
let dummy
const counter = observable({ nested: { num: 0 } })
- autorun(() => (dummy = counter.nested.num))
+ effect(() => (dummy = counter.nested.num))
expect(dummy).toBe(0)
counter.nested.num = 8
it('should observe delete operations', () => {
let dummy
const obj = observable({ prop: 'value' })
- autorun(() => (dummy = obj.prop))
+ effect(() => (dummy = obj.prop))
expect(dummy).toBe('value')
delete obj.prop
it('should observe has operations', () => {
let dummy
const obj: any = observable({ prop: 'value' })
- autorun(() => (dummy = 'prop' in obj))
+ effect(() => (dummy = 'prop' in obj))
expect(dummy).toBe(true)
delete obj.prop
const counter = observable({ num: 0 })
const parentCounter = observable({ num: 2 })
Object.setPrototypeOf(counter, parentCounter)
- autorun(() => (dummy = counter.num))
+ effect(() => (dummy = counter.num))
expect(dummy).toBe(0)
delete counter.num
const counter = observable({ num: 0 })
const parentCounter = observable({ num: 2 })
Object.setPrototypeOf(counter, parentCounter)
- autorun(() => (dummy = 'num' in counter))
+ effect(() => (dummy = 'num' in counter))
expect(dummy).toBe(true)
delete counter.num
}
})
Object.setPrototypeOf(obj, parent)
- autorun(() => (dummy = obj.prop))
- autorun(() => (parentDummy = parent.prop))
+ effect(() => (dummy = obj.prop))
+ effect(() => (parentDummy = parent.prop))
expect(dummy).toBe(undefined)
expect(parentDummy).toBe(undefined)
it('should observe function call chains', () => {
let dummy
const counter = observable({ num: 0 })
- autorun(() => (dummy = getNum()))
+ effect(() => (dummy = getNum()))
function getNum() {
return counter.num
it('should observe iteration', () => {
let dummy
const list = observable(['Hello'])
- autorun(() => (dummy = list.join(' ')))
+ effect(() => (dummy = list.join(' ')))
expect(dummy).toBe('Hello')
list.push('World!')
it('should observe implicit array length changes', () => {
let dummy
const list = observable(['Hello'])
- autorun(() => (dummy = list.join(' ')))
+ effect(() => (dummy = list.join(' ')))
expect(dummy).toBe('Hello')
list[1] = 'World!'
let dummy
const list: any[] = observable([])
list[1] = 'World!'
- autorun(() => (dummy = list.join(' ')))
+ effect(() => (dummy = list.join(' ')))
expect(dummy).toBe(' World!')
list[0] = 'Hello'
it('should observe enumeration', () => {
let dummy = 0
const numbers: any = observable({ num1: 3 })
- autorun(() => {
+ effect(() => {
dummy = 0
for (let key in numbers) {
dummy += numbers[key]
const key = Symbol('symbol keyed prop')
let dummy, hasDummy
const obj = observable({ [key]: 'value' })
- autorun(() => (dummy = obj[key]))
- autorun(() => (hasDummy = key in obj))
+ effect(() => (dummy = obj[key]))
+ effect(() => (hasDummy = key in obj))
expect(dummy).toBe('value')
expect(hasDummy).toBe(true)
const key = Symbol.isConcatSpreadable
let dummy
const array: any = observable([])
- autorun(() => (dummy = array[key]))
+ effect(() => (dummy = array[key]))
expect(array[key]).toBe(undefined)
expect(dummy).toBe(undefined)
let dummy
const obj = observable({ func: oldFunc })
- autorun(() => (dummy = obj.func))
+ effect(() => (dummy = obj.func))
expect(dummy).toBe(oldFunc)
obj.func = newFunc
const getSpy = jest.fn(() => (getDummy = obj.prop))
const hasSpy = jest.fn(() => (hasDummy = 'prop' in obj))
- autorun(getSpy)
- autorun(hasSpy)
+ effect(getSpy)
+ effect(hasSpy)
expect(getDummy).toBe('value')
expect(hasDummy).toBe(true)
it('should not observe raw mutations', () => {
let dummy
const obj: any = observable()
- autorun(() => (dummy = unwrap(obj).prop))
+ effect(() => (dummy = unwrap(obj).prop))
expect(dummy).toBe(undefined)
obj.prop = 'value'
it('should not be triggered by raw mutations', () => {
let dummy
const obj: any = observable()
- autorun(() => (dummy = obj.prop))
+ effect(() => (dummy = obj.prop))
expect(dummy).toBe(undefined)
unwrap(obj).prop = 'value'
}
})
Object.setPrototypeOf(obj, parent)
- autorun(() => (dummy = obj.prop))
- autorun(() => (parentDummy = parent.prop))
+ effect(() => (dummy = obj.prop))
+ effect(() => (parentDummy = parent.prop))
expect(dummy).toBe(undefined)
expect(parentDummy).toBe(undefined)
const counter = observable({ num: 0 })
const counterSpy = jest.fn(() => counter.num++)
- autorun(counterSpy)
+ effect(counterSpy)
expect(counter.num).toBe(1)
expect(counterSpy).toHaveBeenCalledTimes(1)
counter.num = 4
numSpy()
}
})
- autorun(numSpy)
+ effect(numSpy)
expect(counter.num).toEqual(10)
expect(numSpy).toHaveBeenCalledTimes(10)
})
- it('should avoid infinite loops with other autoruns', () => {
+ it('should avoid infinite loops with other effects', () => {
const nums = observable({ num1: 0, num2: 1 })
const spy1 = jest.fn(() => (nums.num1 = nums.num2))
const spy2 = jest.fn(() => (nums.num2 = nums.num1))
- autorun(spy1)
- autorun(spy2)
+ effect(spy1)
+ effect(spy2)
expect(nums.num1).toBe(1)
expect(nums.num2).toBe(1)
expect(spy1).toHaveBeenCalledTimes(1)
function greet() {
return 'Hello World'
}
- const autorun1 = autorun(greet)
- const autorun2 = autorun(greet)
- expect(typeof autorun1).toBe('function')
- expect(typeof autorun2).toBe('function')
- expect(autorun1).not.toBe(greet)
- expect(autorun1).not.toBe(autorun2)
+ const effect1 = effect(greet)
+ const effect2 = effect(greet)
+ expect(typeof effect1).toBe('function')
+ expect(typeof effect2).toBe('function')
+ expect(effect1).not.toBe(greet)
+ expect(effect1).not.toBe(effect2)
})
it('should discover new branches while running automatically', () => {
const conditionalSpy = jest.fn(() => {
dummy = obj.run ? obj.prop : 'other'
})
- autorun(conditionalSpy)
+ effect(conditionalSpy)
expect(dummy).toBe('other')
expect(conditionalSpy).toHaveBeenCalledTimes(1)
let dummy
let run = false
const obj = observable({ prop: 'value' })
- const runner = autorun(() => {
+ const runner = effect(() => {
dummy = run ? obj.prop : 'other'
})
const conditionalSpy = jest.fn(() => {
dummy = obj.run ? obj.prop : 'other'
})
- autorun(conditionalSpy)
+ effect(conditionalSpy)
expect(dummy).toBe('value')
expect(conditionalSpy).toHaveBeenCalledTimes(1)
expect(conditionalSpy).toHaveBeenCalledTimes(2)
})
- it('should not double wrap if the passed function is a autorun', () => {
- const runner = autorun(() => {})
- const otherRunner = autorun(runner)
+ it('should not double wrap if the passed function is a effect', () => {
+ const runner = effect(() => {})
+ const otherRunner = effect(runner)
expect(runner).not.toBe(otherRunner)
expect(runner.raw).toBe(otherRunner.raw)
})
}
dummy = obj.prop
})
- autorun(fnSpy)
+ effect(fnSpy)
expect(fnSpy).toHaveBeenCalledTimes(1)
obj.prop = 16
expect(fnSpy).toHaveBeenCalledTimes(2)
})
- it('should allow nested autoruns', () => {
+ it('should allow nested effects', () => {
const nums = observable({ num1: 0, num2: 1, num3: 2 })
const dummy: any = {}
const childSpy = jest.fn(() => (dummy.num1 = nums.num1))
- const childautorun = autorun(childSpy)
+ const childeffect = effect(childSpy)
const parentSpy = jest.fn(() => {
dummy.num2 = nums.num2
- childautorun()
+ childeffect()
dummy.num3 = nums.num3
})
- autorun(parentSpy)
+ effect(parentSpy)
expect(dummy).toEqual({ num1: 0, num2: 1, num3: 2 })
expect(parentSpy).toHaveBeenCalledTimes(1)
expect(childSpy).toHaveBeenCalledTimes(2)
- // this should only call the childautorun
+ // this should only call the childeffect
nums.num1 = 4
expect(dummy).toEqual({ num1: 4, num2: 1, num3: 2 })
expect(parentSpy).toHaveBeenCalledTimes(1)
expect(childSpy).toHaveBeenCalledTimes(3)
- // this calls the parentautorun, which calls the childautorun once
+ // this calls the parenteffect, which calls the childeffect once
nums.num2 = 10
expect(dummy).toEqual({ num1: 4, num2: 10, num3: 2 })
expect(parentSpy).toHaveBeenCalledTimes(2)
expect(childSpy).toHaveBeenCalledTimes(4)
- // this calls the parentautorun, which calls the childautorun once
+ // this calls the parenteffect, which calls the childeffect once
nums.num3 = 7
expect(dummy).toEqual({ num1: 4, num2: 10, num3: 7 })
expect(parentSpy).toHaveBeenCalledTimes(3)
}
const model = observable(new Model())
let dummy
- autorun(() => {
+ effect(() => {
dummy = model.count
})
expect(dummy).toBe(0)
runner = _runner
})
const obj = observable({ foo: 1 })
- autorun(
+ effect(
() => {
dummy = obj.foo
},
events.push(e)
})
const obj = observable({ foo: 1, bar: 2 })
- const runner = autorun(
+ const runner = effect(
() => {
dummy = obj.foo
dummy = 'bar' in obj
expect(onTrack).toHaveBeenCalledTimes(3)
expect(events).toEqual([
{
- runner,
+ effect: runner,
target: unwrap(obj),
type: OperationTypes.GET,
key: 'foo'
},
{
- runner,
+ effect: runner,
target: unwrap(obj),
type: OperationTypes.HAS,
key: 'bar'
},
{
- runner,
+ effect: runner,
target: unwrap(obj),
type: OperationTypes.ITERATE,
key: ITERATE_KEY
events.push(e)
})
const obj = observable({ foo: 1 })
- const runner = autorun(
+ const runner = effect(
() => {
dummy = obj.foo
},
expect(dummy).toBe(2)
expect(onTrigger).toHaveBeenCalledTimes(1)
expect(events[0]).toEqual({
- runner,
+ effect: runner,
target: unwrap(obj),
type: OperationTypes.SET,
key: 'foo',
expect(dummy).toBeUndefined()
expect(onTrigger).toHaveBeenCalledTimes(2)
expect(events[1]).toEqual({
- runner,
+ effect: runner,
target: unwrap(obj),
type: OperationTypes.DELETE,
key: 'foo',
it('stop', () => {
let dummy
const obj = observable({ prop: 1 })
- const runner = autorun(() => {
+ const runner = effect(() => {
dummy = obj.prop
})
obj.prop = 2
obj.prop = 3
expect(dummy).toBe(2)
- // stopped runner should still be manually callable
+ // stopped effect should still be manually callable
runner()
expect(dummy).toBe(3)
})
})
})
let dummy
- autorun(() => {
+ effect(() => {
dummy = obj.foo.prop
})
expect(dummy).toBe(0)
markImmutable,
lock,
unlock,
- autorun
+ effect
} from '../src'
describe('observer/immutable', () => {
expect(warn).not.toHaveBeenCalled()
})
- it('should not trigger autoruns when locked', () => {
+ it('should not trigger effects when locked', () => {
const observed = immutable({ a: 1 })
let dummy
- autorun(() => {
+ effect(() => {
dummy = observed.a
})
expect(dummy).toBe(1)
expect(dummy).toBe(1)
})
- it('should trigger autoruns when unlocked', () => {
+ it('should trigger effects when unlocked', () => {
const observed = immutable({ a: 1 })
let dummy
- autorun(() => {
+ effect(() => {
dummy = observed.a
})
expect(dummy).toBe(1)
expect(warn).not.toHaveBeenCalled()
})
- it('should not trigger autoruns when locked', () => {
+ it('should not trigger effects when locked', () => {
const observed = immutable([{ a: 1 }])
let dummy
- autorun(() => {
+ effect(() => {
dummy = observed[0].a
})
expect(dummy).toBe(1)
expect(dummy).toBe(1)
})
- it('should trigger autoruns when unlocked', () => {
+ it('should trigger effects when unlocked', () => {
const observed = immutable([{ a: 1 }])
let dummy
- autorun(() => {
+ effect(() => {
dummy = observed[0].a
})
expect(dummy).toBe(1)
expect(isImmutable(original.get(key1))).toBe(false)
})
- test('should not allow mutation & not trigger autorun', () => {
+ test('should not allow mutation & not trigger effect', () => {
const map = immutable(new Collection())
const key = {}
let dummy
- autorun(() => {
+ effect(() => {
dummy = map.get(key)
})
expect(dummy).toBeUndefined()
expect(warn).toHaveBeenCalledTimes(1)
})
- test('should allow mutation & trigger autorun when unlocked', () => {
+ test('should allow mutation & trigger effect when unlocked', () => {
const map = immutable(new Collection())
const isWeak = Collection === WeakMap
const key = {}
let dummy
- autorun(() => {
+ effect(() => {
dummy = map.get(key) + (isWeak ? 0 : map.size)
})
expect(dummy).toBeNaN()
expect(original.has(observable(key1))).toBe(false)
})
- test('should not allow mutation & not trigger autorun', () => {
+ test('should not allow mutation & not trigger effect', () => {
const set = immutable(new Collection())
const key = {}
let dummy
- autorun(() => {
+ effect(() => {
dummy = set.has(key)
})
expect(dummy).toBe(false)
expect(warn).toHaveBeenCalledTimes(1)
})
- test('should allow mutation & trigger autorun when unlocked', () => {
+ test('should allow mutation & trigger effect when unlocked', () => {
const set = immutable(new Collection())
const key = {}
let dummy
- autorun(() => {
+ effect(() => {
dummy = set.has(key)
})
expect(dummy).toBe(false)
+++ /dev/null
-import { OperationTypes } from './operations'
-import { Dep, KeyToDepMap, targetMap } from './state'
-
-export interface Autorun {
- (): any
- isAutorun: true
- active: boolean
- raw: Function
- deps: Array<Dep>
- computed?: boolean
- scheduler?: Scheduler
- onTrack?: Debugger
- onTrigger?: Debugger
-}
-
-export interface AutorunOptions {
- lazy?: boolean
- scheduler?: Scheduler
- onTrack?: Debugger
- onTrigger?: Debugger
-}
-
-export type Scheduler = (run: () => any) => void
-
-export type DebuggerEvent = {
- runner: Autorun
- target: any
- type: OperationTypes
- key: string | symbol | undefined
-}
-
-export type Debugger = (event: DebuggerEvent) => void
-
-export const activeAutorunStack: Autorun[] = []
-
-export const ITERATE_KEY = Symbol('iterate')
-
-export function createAutorun(fn: Function, options: AutorunOptions): Autorun {
- const runner = function runner(...args): any {
- return run(runner as Autorun, fn, args)
- } as Autorun
- runner.isAutorun = true
- runner.active = true
- runner.raw = fn
- runner.scheduler = options.scheduler
- runner.onTrack = options.onTrack
- runner.onTrigger = options.onTrigger
- runner.deps = []
- return runner
-}
-
-function run(runner: Autorun, fn: Function, args: any[]): any {
- if (!runner.active) {
- return fn(...args)
- }
- if (activeAutorunStack.indexOf(runner) === -1) {
- cleanup(runner)
- try {
- activeAutorunStack.push(runner)
- return fn(...args)
- } finally {
- activeAutorunStack.pop()
- }
- }
-}
-
-export function cleanup(runner: Autorun) {
- for (let i = 0; i < runner.deps.length; i++) {
- runner.deps[i].delete(runner)
- }
- runner.deps = []
-}
-
-export function track(
- target: any,
- type: OperationTypes,
- key?: string | symbol
-) {
- const runner = activeAutorunStack[activeAutorunStack.length - 1]
- if (runner) {
- if (type === OperationTypes.ITERATE) {
- key = ITERATE_KEY
- }
- // keyMap must exist because only an observed target can call this function
- const depsMap = targetMap.get(target) as KeyToDepMap
- let dep = depsMap.get(key as string | symbol)
- if (!dep) {
- depsMap.set(key as string | symbol, (dep = new Set()))
- }
- if (!dep.has(runner)) {
- dep.add(runner)
- runner.deps.push(dep)
- if (__DEV__ && runner.onTrack) {
- runner.onTrack({
- runner,
- target,
- type,
- key
- })
- }
- }
- }
-}
-
-export function trigger(
- target: any,
- type: OperationTypes,
- key?: string | symbol,
- extraInfo?: any
-) {
- const depsMap = targetMap.get(target) as KeyToDepMap
- const runners = new Set()
- const computedRunners = new Set()
- if (type === OperationTypes.CLEAR) {
- // collection being cleared, trigger all runners for target
- depsMap.forEach(dep => {
- addRunners(runners, computedRunners, dep)
- })
- } else {
- // schedule runs for SET | ADD | DELETE
- if (key !== void 0) {
- addRunners(runners, computedRunners, depsMap.get(key as string | symbol))
- }
- // also run for iteration key on ADD | DELETE
- if (type === OperationTypes.ADD || type === OperationTypes.DELETE) {
- const iterationKey = Array.isArray(target) ? 'length' : ITERATE_KEY
- addRunners(runners, computedRunners, depsMap.get(iterationKey))
- }
- }
- const run = (runner: Autorun) => {
- scheduleRun(runner, target, type, key, extraInfo)
- }
- // Important: computed runners must be run first so that computed getters
- // can be invalidated before any normal runners that depend on them are run.
- computedRunners.forEach(run)
- runners.forEach(run)
-}
-
-function addRunners(
- runners: Set<Autorun>,
- computedRunners: Set<Autorun>,
- runnersToAdd: Set<Autorun> | undefined
-) {
- if (runnersToAdd !== void 0) {
- runnersToAdd.forEach(runner => {
- if (runner.computed) {
- computedRunners.add(runner)
- } else {
- runners.add(runner)
- }
- })
- }
-}
-
-function scheduleRun(
- runner: Autorun,
- target: any,
- type: OperationTypes,
- key: string | symbol | undefined,
- extraInfo: any
-) {
- if (__DEV__ && runner.onTrigger) {
- runner.onTrigger(
- Object.assign(
- {
- runner,
- target,
- key,
- type
- },
- extraInfo
- )
- )
- }
- if (runner.scheduler !== void 0) {
- runner.scheduler(runner)
- } else {
- runner()
- }
-}
import { observable, immutable, unwrap } from './index'
import { OperationTypes } from './operations'
-import { track, trigger } from './autorun'
+import { track, trigger } from './effect'
import { LOCKED } from './lock'
import { isObject } from '@vue/shared'
import { unwrap, observable, immutable } from './index'
-import { track, trigger } from './autorun'
+import { track, trigger } from './effect'
import { OperationTypes } from './operations'
import { LOCKED } from './lock'
import { isObject } from '@vue/shared'
-import { autorun } from './index'
-import { Autorun, activeAutorunStack } from './autorun'
+import { effect } from './index'
+import { ReactiveEffect, activeReactiveEffectStack } from './effect'
export interface ComputedGetter<T = any> {
(): T
- runner: Autorun
+ effect: ReactiveEffect
}
export function computed<T, C = null>(
): ComputedGetter<T> {
let dirty: boolean = true
let value: any = undefined
- const runner = autorun(() => getter.call(context, context), {
+ const runner = effect(() => getter.call(context, context), {
lazy: true,
scheduler: () => {
dirty = true
value = runner()
dirty = false
}
- // When computed autoruns are accessed in a parent autorun, the parent
+ // When computed effects are accessed in a parent effect, the parent
// should track all the dependencies the computed property has tracked.
// This should also apply for chained computed properties.
trackChildRun(runner)
return value
}) as ComputedGetter
- // expose runner so computed can be stopped
- computedGetter.runner = runner
- // mark runner as computed so that it gets priority during trigger
+ // expose effect so computed can be stopped
+ computedGetter.effect = runner
+ // mark effect as computed so that it gets priority during trigger
runner.computed = true
return computedGetter
}
-function trackChildRun(childRunner: Autorun) {
- const parentRunner = activeAutorunStack[activeAutorunStack.length - 1]
+function trackChildRun(childRunner: ReactiveEffect) {
+ const parentRunner =
+ activeReactiveEffectStack[activeReactiveEffectStack.length - 1]
if (parentRunner) {
for (let i = 0; i < childRunner.deps.length; i++) {
const dep = childRunner.deps[i]
--- /dev/null
+import { OperationTypes } from './operations'
+import { Dep, KeyToDepMap, targetMap } from './state'
+
+export interface ReactiveEffect {
+ (): any
+ isEffect: true
+ active: boolean
+ raw: Function
+ deps: Array<Dep>
+ computed?: boolean
+ scheduler?: Scheduler
+ onTrack?: Debugger
+ onTrigger?: Debugger
+}
+
+export interface ReactiveEffectOptions {
+ lazy?: boolean
+ scheduler?: Scheduler
+ onTrack?: Debugger
+ onTrigger?: Debugger
+}
+
+export type Scheduler = (run: () => any) => void
+
+export type DebuggerEvent = {
+ effect: ReactiveEffect
+ target: any
+ type: OperationTypes
+ key: string | symbol | undefined
+}
+
+export type Debugger = (event: DebuggerEvent) => void
+
+export const activeReactiveEffectStack: ReactiveEffect[] = []
+
+export const ITERATE_KEY = Symbol('iterate')
+
+export function createReactiveEffect(
+ fn: Function,
+ options: ReactiveEffectOptions
+): ReactiveEffect {
+ const effect = function effect(...args): any {
+ return run(effect as ReactiveEffect, fn, args)
+ } as ReactiveEffect
+ effect.isEffect = true
+ effect.active = true
+ effect.raw = fn
+ effect.scheduler = options.scheduler
+ effect.onTrack = options.onTrack
+ effect.onTrigger = options.onTrigger
+ effect.deps = []
+ return effect
+}
+
+function run(effect: ReactiveEffect, fn: Function, args: any[]): any {
+ if (!effect.active) {
+ return fn(...args)
+ }
+ if (activeReactiveEffectStack.indexOf(effect) === -1) {
+ cleanup(effect)
+ try {
+ activeReactiveEffectStack.push(effect)
+ return fn(...args)
+ } finally {
+ activeReactiveEffectStack.pop()
+ }
+ }
+}
+
+export function cleanup(effect: ReactiveEffect) {
+ for (let i = 0; i < effect.deps.length; i++) {
+ effect.deps[i].delete(effect)
+ }
+ effect.deps = []
+}
+
+export function track(
+ target: any,
+ type: OperationTypes,
+ key?: string | symbol
+) {
+ const effect = activeReactiveEffectStack[activeReactiveEffectStack.length - 1]
+ if (effect) {
+ if (type === OperationTypes.ITERATE) {
+ key = ITERATE_KEY
+ }
+ // keyMap must exist because only an observed target can call this function
+ const depsMap = targetMap.get(target) as KeyToDepMap
+ let dep = depsMap.get(key as string | symbol)
+ if (!dep) {
+ depsMap.set(key as string | symbol, (dep = new Set()))
+ }
+ if (!dep.has(effect)) {
+ dep.add(effect)
+ effect.deps.push(dep)
+ if (__DEV__ && effect.onTrack) {
+ effect.onTrack({
+ effect,
+ target,
+ type,
+ key
+ })
+ }
+ }
+ }
+}
+
+export function trigger(
+ target: any,
+ type: OperationTypes,
+ key?: string | symbol,
+ extraInfo?: any
+) {
+ const depsMap = targetMap.get(target) as KeyToDepMap
+ const effects = new Set()
+ const computedRunners = new Set()
+ if (type === OperationTypes.CLEAR) {
+ // collection being cleared, trigger all effects for target
+ depsMap.forEach(dep => {
+ addRunners(effects, computedRunners, dep)
+ })
+ } else {
+ // schedule runs for SET | ADD | DELETE
+ if (key !== void 0) {
+ addRunners(effects, computedRunners, depsMap.get(key as string | symbol))
+ }
+ // also run for iteration key on ADD | DELETE
+ if (type === OperationTypes.ADD || type === OperationTypes.DELETE) {
+ const iterationKey = Array.isArray(target) ? 'length' : ITERATE_KEY
+ addRunners(effects, computedRunners, depsMap.get(iterationKey))
+ }
+ }
+ const run = (effect: ReactiveEffect) => {
+ scheduleRun(effect, target, type, key, extraInfo)
+ }
+ // Important: computed effects must be run first so that computed getters
+ // can be invalidated before any normal effects that depend on them are run.
+ computedRunners.forEach(run)
+ effects.forEach(run)
+}
+
+function addRunners(
+ effects: Set<ReactiveEffect>,
+ computedRunners: Set<ReactiveEffect>,
+ effectsToAdd: Set<ReactiveEffect> | undefined
+) {
+ if (effectsToAdd !== void 0) {
+ effectsToAdd.forEach(effect => {
+ if (effect.computed) {
+ computedRunners.add(effect)
+ } else {
+ effects.add(effect)
+ }
+ })
+ }
+}
+
+function scheduleRun(
+ effect: ReactiveEffect,
+ target: any,
+ type: OperationTypes,
+ key: string | symbol | undefined,
+ extraInfo: any
+) {
+ if (__DEV__ && effect.onTrigger) {
+ effect.onTrigger(
+ Object.assign(
+ {
+ effect,
+ target,
+ key,
+ type
+ },
+ extraInfo
+ )
+ )
+ }
+ if (effect.scheduler !== void 0) {
+ effect.scheduler(effect)
+ } else {
+ effect()
+ }
+}
} from './state'
import {
- createAutorun,
+ createReactiveEffect,
cleanup,
- Autorun,
- AutorunOptions,
+ ReactiveEffect,
+ ReactiveEffectOptions,
DebuggerEvent
-} from './autorun'
+} from './effect'
-export { Autorun, AutorunOptions, DebuggerEvent }
+export { ReactiveEffect, ReactiveEffectOptions, DebuggerEvent }
export { OperationTypes } from './operations'
export { computed, ComputedGetter } from './computed'
export { lock, unlock } from './lock'
return observed
}
-export function autorun(
+export function effect(
fn: Function,
- options: AutorunOptions = EMPTY_OBJ
-): Autorun {
- if ((fn as Autorun).isAutorun) {
- fn = (fn as Autorun).raw
+ options: ReactiveEffectOptions = EMPTY_OBJ
+): ReactiveEffect {
+ if ((fn as ReactiveEffect).isEffect) {
+ fn = (fn as ReactiveEffect).raw
}
- const runner = createAutorun(fn, options)
+ const effect = createReactiveEffect(fn, options)
if (!options.lazy) {
- runner()
+ effect()
}
- return runner
+ return effect
}
-export function stop(runner: Autorun) {
- if (runner.active) {
- cleanup(runner)
- runner.active = false
+export function stop(effect: ReactiveEffect) {
+ if (effect.active) {
+ cleanup(effect)
+ effect.active = false
}
}
-import { Autorun } from './autorun'
+import { ReactiveEffect } from './effect'
// The main WeakMap that stores {target -> key -> dep} connections.
// Conceptually, it's easier to think of a dependency as a Dep class
// which maintains a Set of subscribers, but we simply store them as
// raw Sets to reduce memory overhead.
-export type Dep = Set<Autorun>
+export type Dep = Set<ReactiveEffect>
export type KeyToDepMap = Map<string | symbol, Dep>
export const targetMap: WeakMap<any, KeyToDepMap> = new WeakMap()
nextTick,
resetOps,
dumpOps,
- NodeOpTypes
+ NodeOpTypes,
+ createFragment,
+ createTextVNode
} from '@vue/runtime-test'
describe('Fragments', () => {
class App extends Component {
render() {
return state.ok
- ? h.f([h('div', 'one'), h.t('two')], ChildrenFlags.NONE_KEYED_VNODES)
- : h.f(
- [h('div', 'foo'), h.t('bar'), h.t('baz')],
+ ? createFragment(
+ [h('div', 'one'), createTextVNode('two')],
+ ChildrenFlags.NONE_KEYED_VNODES
+ )
+ : createFragment(
+ [h('div', 'foo'), createTextVNode('bar'), createTextVNode('baz')],
ChildrenFlags.NONE_KEYED_VNODES
)
}
WatchOptions
} from './componentOptions'
import { setupWatcher } from './componentWatch'
-import { Autorun, DebuggerEvent, ComputedGetter } from '@vue/observer'
+import { ReactiveEffect, DebuggerEvent, ComputedGetter } from '@vue/observer'
import { nextTick } from '@vue/scheduler'
import { ErrorTypes } from './errorHandling'
import { initializeComponentInstance } from './componentUtils'
$children: ComponentInstance[]
$options: ComponentOptions<P, D>
- _updateHandle: Autorun
+ _update: ReactiveEffect
_queueJob: ((fn: () => void) => void)
_self: ComponentInstance<P, D> // on proxies only
}
_rawData: Data | null = null
_computedGetters: Record<string, ComputedGetter> | null = null
- _watchHandles: Set<Autorun> | null = null
+ _watchHandles: Set<ReactiveEffect> | null = null
_mounted: boolean = false
_unmounted: boolean = false
_events: { [event: string]: Function[] | null } | null = null
- _updateHandle: Autorun | null = null
+ _update: ReactiveEffect | null = null
_queueJob: ((fn: () => void) => void) | null = null
_isVue: boolean = true
_inactiveRoot: boolean = false
const handles = instance._computedGetters
if (handles !== null) {
for (const key in handles) {
- stop(handles[key].runner)
+ stop(handles[key].effect)
}
}
}
1
)
}
- stop(instance._updateHandle)
+ stop(instance._update)
teardownComputed(instance)
teardownWatch(instance)
}
} from '@vue/shared'
import { ComponentInstance } from './component'
import { ComponentWatchOptions, WatchOptions } from './componentOptions'
-import { autorun, stop } from '@vue/observer'
+import { effect, stop } from '@vue/observer'
import { queueJob } from '@vue/scheduler'
import { handleError, ErrorTypes } from './errorHandling'
import { warn } from './warning'
}
}
- const runner = autorun(getter, {
+ const runner = effect(getter, {
lazy: true,
scheduler: options.sync
? applyCb
import {
- autorun,
- stop,
- Autorun,
+ effect as createReactiveEffect,
+ stop as stopReactiveEffect,
+ ReactiveEffect,
immutable,
- AutorunOptions
+ ReactiveEffectOptions
} from '@vue/observer'
import {
queueJob,
handleSchedulerError,
nextTick,
- queueEffect,
+ queuePostEffect,
flushEffects,
queueNodeOp
} from '@vue/scheduler'
export interface FunctionalHandle {
prev: VNode
next: VNode
- update: Autorun
+ update: ReactiveEffect
container: RenderNode | null
}
queueInsertOrAppend(container, el, endNode)
}
if (ref) {
- queueEffect(() => {
+ queuePostEffect(() => {
ref(el)
})
}
if (data != null && data.vnodeMounted) {
- queueEffect(() => {
+ queuePostEffect(() => {
data.vnodeMounted(vnode)
})
}
})
const doMount = () => {
- handle.update = autorun(
+ handle.update = createReactiveEffect(
() => {
if (!handle.next) {
// initial mount
pushWarningContext(vnode)
}
const subTree = (vnode.children = renderFunctionalRoot(vnode))
- queueEffect(() => {
+ queuePostEffect(() => {
vnode.el = subTree.el as RenderNode
})
mount(subTree, container, vnode as MountedVNode, isSVG, endNode)
doMount()
// cleanup if mount is invalidated before committed
return () => {
- stop(handle.update)
+ stopReactiveEffect(handle.update)
}
})
}
}
const prevTree = prev.children as MountedVNode
const nextTree = (next.children = renderFunctionalRoot(next))
- queueEffect(() => {
+ queuePostEffect(() => {
next.el = nextTree.el
})
patch(
const { children, childFlags } = vnode
switch (childFlags) {
case ChildrenFlags.SINGLE_VNODE:
- queueEffect(() => {
+ queuePostEffect(() => {
vnode.el = (children as MountedVNode).el
})
mount(children as VNode, container, contextVNode, isSVG, endNode)
vnode.el = placeholder.el
break
default:
- queueEffect(() => {
+ queuePostEffect(() => {
vnode.el = (children as MountedVNode[])[0].el
})
mountArrayChildren(
)
}
if (ref) {
- queueEffect(() => {
+ queuePostEffect(() => {
ref(target)
})
}
// then retrieve its next sibling to use as the end node for patchChildren.
const endNode = platformNextSibling(getVNodeLastEl(prevVNode))
const { childFlags, children } = nextVNode
- queueEffect(() => {
+ queuePostEffect(() => {
switch (childFlags) {
case ChildrenFlags.SINGLE_VNODE:
nextVNode.el = (children as MountedVNode).el
}
} else {
// functional
- stop((handle as FunctionalHandle).update)
+ stopReactiveEffect((handle as FunctionalHandle).update)
unmount(children as MountedVNode)
}
} else if (flags & VNodeFlags.PORTAL) {
} = instance
instance.$forceUpdate = () => {
- queueJob(instance._updateHandle)
+ queueJob(instance._update)
}
- const autorunOptions: AutorunOptions = {
+ const effectOptions: ReactiveEffectOptions = {
scheduler: queueJob
}
if (__DEV__) {
if (renderTracked) {
- autorunOptions.onTrack = event => {
+ effectOptions.onTrack = event => {
callLifecycleHookWithHandler(
renderTracked,
$proxy,
}
}
if (renderTriggered) {
- autorunOptions.onTrigger = event => {
+ effectOptions.onTrigger = event => {
callLifecycleHookWithHandler(
renderTriggered,
$proxy,
}
}
- instance._updateHandle = autorun(() => {
+ instance._update = createReactiveEffect(() => {
if (instance._unmounted) {
return
}
instance.$vnode = renderInstanceRoot(instance) as MountedVNode
- queueEffect(() => {
+ queuePostEffect(() => {
vnode.el = instance.$vnode.el
if (__COMPAT__) {
// expose __vue__ for devtools
mount(instance.$vnode, container, vnode as MountedVNode, isSVG, endNode)
}
- }, autorunOptions)
+ }, effectOptions)
if (__DEV__) {
popWarningContext()
const nextVNode = renderInstanceRoot(instance) as MountedVNode
- queueEffect(() => {
+ queuePostEffect(() => {
instance.$vnode = nextVNode
const el = nextVNode.el as RenderNode
if (__COMPAT__) {
if (__DEV__) {
popWarningContext()
}
- queueEffect(() => {
+ queuePostEffect(() => {
callActivatedHook(instance, true)
})
}
-import { queueJob, queueEffect, nextTick } from '../src/index'
+import { queueJob, queuePostEffect, nextTick } from '../src/index'
describe('scheduler', () => {
it('queueJob', async () => {
const calls: any = []
const job1 = () => {
calls.push('job1')
- queueEffect(cb1)
+ queuePostEffect(cb1)
}
const job2 = () => {
calls.push('job2')
- queueEffect(cb2)
+ queuePostEffect(cb2)
}
const cb1 = () => {
calls.push('cb1')
const calls: any = []
const job1 = () => {
calls.push('job1')
- queueEffect(cb1)
+ queuePostEffect(cb1)
// job1 queues job2
queueJob(job2)
}
const job2 = () => {
calls.push('job2')
- queueEffect(cb2)
+ queuePostEffect(cb2)
}
const cb1 = () => {
calls.push('cb1')
expect(calls).toEqual(['job1', 'job2'])
})
- it('queueJob inside postCommitCb', async () => {
+ it('queueJob inside postEffect', async () => {
const calls: any = []
const job1 = () => {
calls.push('job1')
- queueEffect(cb1)
+ queuePostEffect(cb1)
}
const cb1 = () => {
// queue another job in postFlushCb
}
const job2 = () => {
calls.push('job2')
- queueEffect(cb2)
+ queuePostEffect(cb2)
}
const cb2 = () => {
calls.push('cb2')
ops: Op[]
// Any post DOM mutation side-effects (updated / mounted hooks, refs) are
// buffered inside the job's effects queue.
- // Effects are queued by calling `queueEffect` inside the job function.
- effects: Function[]
+ // Effects are queued by calling `queuePostEffect` inside the job function.
+ postEffects: Function[]
// A job may queue other jobs (e.g. a parent component update triggers the
// update of a child component). Jobs queued by another job is kept in the
// parent's children array, so that in case the parent job is invalidated,
// all its children can be invalidated as well (recursively).
children: Job[]
// Sometimes it's inevitable for a stage fn to produce some side effects
- // (e.g. a component instance sets up an Autorun). In those cases the stage fn
+ // (e.g. a component instance sets up an ReactiveEffect). In those cases the stage fn
// can return a cleanup function which will be called when the job is
// invalidated.
cleanup: T | null
// This is the main API of the scheduler. The raw job can actually be any
// function, but since they are invalidated by identity, it is important that
// a component's update job is a consistent function across its lifecycle -
-// in the renderer, it's actually instance._updateHandle which is in turn
-// an Autorun function.
+// in the renderer, it's actually instance._update which is in turn
+// an ReactiveEffect function.
export function queueJob(rawJob: Function) {
const job = rawJob as Job
if (currentJob) {
}
}
-export function queueEffect(fn: Function) {
+export function queuePostEffect(fn: Function) {
if (currentJob) {
- currentJob.effects.push(fn)
+ currentJob.postEffects.push(fn)
} else {
postEffectsQueue.push(fn)
}
function resetJob(job: Job) {
job.ops.length = 0
- job.effects.length = 0
+ job.postEffects.length = 0
job.children.length = 0
}
function queueJobForStaging(job: Job) {
job.ops = job.ops || []
- job.effects = job.effects || []
+ job.postEffects = job.postEffects || []
job.children = job.children || []
resetJob(job)
// inherit parent job's expiration deadline
}
function commitJob(job: Job) {
- const { ops, effects } = job
+ const { ops, postEffects } = job
for (let i = 0; i < ops.length; i++) {
applyOp(ops[i])
}
// queue post commit cbs
- if (effects) {
- postEffectsQueue.push(...effects)
+ if (postEffects) {
+ postEffectsQueue.push(...postEffects)
}
resetJob(job)
job.status = JobStatus.IDLE