diff --git a/packages/@ember/-internals/environment/lib/env.ts b/packages/@ember/-internals/environment/lib/env.ts index fab88cf6687..65463301d69 100644 --- a/packages/@ember/-internals/environment/lib/env.ts +++ b/packages/@ember/-internals/environment/lib/env.ts @@ -112,6 +112,20 @@ export const ENV = { */ _JQUERY_INTEGRATION: true, + /** + Whether the app defaults to using async observers. + + This is not intended to be set directly, as the implementation may change in + the future. Use `@ember/optional-features` instead. + + @property _DEFAULT_ASYNC_OBSERVERS + @for EmberENV + @type Boolean + @default false + @private + */ + _DEFAULT_ASYNC_OBSERVERS: false, + /** Controls the maximum number of scheduled rerenders without "settling". In general, applications should not need to modify this environment variable, but please diff --git a/packages/@ember/-internals/meta/lib/meta.ts b/packages/@ember/-internals/meta/lib/meta.ts index 3d54fd98906..2a60290e56c 100644 --- a/packages/@ember/-internals/meta/lib/meta.ts +++ b/packages/@ember/-internals/meta/lib/meta.ts @@ -76,6 +76,7 @@ interface StringListener { target: null; method: string; kind: ListenerKind.ADD | ListenerKind.ONCE | ListenerKind.REMOVE; + sync: boolean; } interface FunctionListener { @@ -83,6 +84,7 @@ interface FunctionListener { target: object | null; method: Function; kind: ListenerKind.ADD | ListenerKind.ONCE | ListenerKind.REMOVE; + sync: boolean; } type Listener = StringListener | FunctionListener; @@ -528,13 +530,14 @@ export class Meta { eventName: string, target: object | null, method: Function | string, - once: boolean + once: boolean, + sync: boolean ) { if (DEBUG) { counters!.addToListenersCalls++; } - this.pushListener(eventName, target, method, once ? ListenerKind.ONCE : ListenerKind.ADD); + this.pushListener(eventName, target, method, once ? ListenerKind.ONCE : ListenerKind.ADD, sync); } removeFromListeners(eventName: string, target: object | null, method: Function | string): void { @@ -549,7 +552,8 @@ export class Meta { event: string, target: object | null, method: Function | string, - kind: ListenerKind.ADD | ListenerKind.ONCE | ListenerKind.REMOVE + kind: ListenerKind.ADD | ListenerKind.ONCE | ListenerKind.REMOVE, + sync = false ): void { let listeners = this.writableListeners(); @@ -585,9 +589,11 @@ export class Meta { target, method, kind, + sync, } as Listener); } else { let listener = listeners[i]; + // If the listener is our own function listener and we are trying to // remove it, we want to splice it out entirely so we don't hold onto a // reference. @@ -598,8 +604,20 @@ export class Meta { ) { listeners.splice(i, 1); } else { + assert( + `You attempted to add an observer for the same method on '${ + event.split(':')[0] + }' twice to ${target} as both sync and async. Observers must be either sync or async, they cannot be both. This is likely a mistake, you should either remove the code that added the observer a second time, or update it to always be sync or async. The method was ${method}.`, + !( + listener.kind === ListenerKind.ADD && + kind === ListenerKind.ADD && + listener.sync !== sync + ) + ); + // update own listener listener.kind = kind; + listener.sync = sync; } } } @@ -761,7 +779,7 @@ export class Meta { result = [] as any[]; } - result.push(listener.event); + result.push(listener); } } } diff --git a/packages/@ember/-internals/metal/index.ts b/packages/@ember/-internals/metal/index.ts index c69d2b77557..6708d17b3bb 100644 --- a/packages/@ember/-internals/metal/index.ts +++ b/packages/@ember/-internals/metal/index.ts @@ -51,12 +51,7 @@ export { default as getProperties } from './lib/get_properties'; export { default as setProperties } from './lib/set_properties'; export { default as expandProperties } from './lib/expand_properties'; -export { - addObserver, - activateObserver, - removeObserver, - flushInvalidActiveObservers, -} from './lib/observer'; +export { addObserver, activateObserver, removeObserver, flushAsyncObservers } from './lib/observer'; export { Mixin, aliasMethod, mixin, observer, applyMixin } from './lib/mixin'; export { default as inject, DEBUG_INJECTION_FUNCTIONS } from './lib/injected_property'; export { tagForProperty, tagFor, markObjectAsDirty, UNKNOWN_PROPERTY_TAG } from './lib/tags'; diff --git a/packages/@ember/-internals/metal/lib/chain-tags.ts b/packages/@ember/-internals/metal/lib/chain-tags.ts index 073070e0b6e..b048d817a93 100644 --- a/packages/@ember/-internals/metal/lib/chain-tags.ts +++ b/packages/@ember/-internals/metal/lib/chain-tags.ts @@ -17,7 +17,7 @@ export function finishLazyChains(obj: any, key: string, value: any) { } if (value === null || (typeof value !== 'object' && typeof value !== 'function')) { - lazyTags.clear(); + lazyTags.length = 0; return; } diff --git a/packages/@ember/-internals/metal/lib/computed.ts b/packages/@ember/-internals/metal/lib/computed.ts index 3d444d28610..6081b3d9606 100644 --- a/packages/@ember/-internals/metal/lib/computed.ts +++ b/packages/@ember/-internals/metal/lib/computed.ts @@ -30,6 +30,7 @@ import { isClassicDecorator, } from './descriptor_map'; import expandProperties from './expand_properties'; +import { setObserverSuspended } from './observer'; import { defineProperty } from './properties'; import { notifyPropertyChange } from './property_events'; import { set } from './property_set'; @@ -667,7 +668,19 @@ export class ComputedProperty extends ComputedDescriptor { let hadCachedValue = cache.has(keyName); let cachedValue = cache.get(keyName); - let ret = this._setter!.call(obj, keyName, value, cachedValue); + let ret; + + if (EMBER_METAL_TRACKED_PROPERTIES) { + setObserverSuspended(obj, keyName, true); + + try { + ret = this._setter!.call(obj, keyName, value, cachedValue); + } finally { + setObserverSuspended(obj, keyName, false); + } + } else { + ret = this._setter!.call(obj, keyName, value, cachedValue); + } // allows setter to return the same value that is cached already if (hadCachedValue && cachedValue === ret) { diff --git a/packages/@ember/-internals/metal/lib/events.ts b/packages/@ember/-internals/metal/lib/events.ts index 0dd230bc06e..4fbfb161938 100644 --- a/packages/@ember/-internals/metal/lib/events.ts +++ b/packages/@ember/-internals/metal/lib/events.ts @@ -41,7 +41,8 @@ export function addListener( eventName: string, target: object | Function | null, method?: Function | string, - once?: boolean + once?: boolean, + sync = true ): void { assert( 'You must pass at least an object and event name to addListener', @@ -53,7 +54,7 @@ export function addListener( target = null; } - metaFor(obj).addToListeners(eventName, target, method!, once === true); + metaFor(obj).addToListeners(eventName, target, method!, once === true, sync); } /** diff --git a/packages/@ember/-internals/metal/lib/mixin.ts b/packages/@ember/-internals/metal/lib/mixin.ts index d8dd8dcbd75..b6dce62fc6e 100644 --- a/packages/@ember/-internals/metal/lib/mixin.ts +++ b/packages/@ember/-internals/metal/lib/mixin.ts @@ -1,6 +1,7 @@ /** @module @ember/object */ +import { ENV } from '@ember/-internals/environment'; import { Meta, meta as metaFor, peekMeta } from '@ember/-internals/meta'; import { getListeners, @@ -395,20 +396,23 @@ if (ALIAS_METHOD) { }; } -function updateObserversAndListeners( - obj: object, - key: string, - paths: string[] | undefined, - updateMethod: ( - obj: object, - path: string, - target: object | Function | null, - method: string - ) => void -) { - if (paths) { - for (let i = 0; i < paths.length; i++) { - updateMethod(obj, paths[i], null, key); +function updateObserversAndListeners(obj: object, key: string, fn: Function, add: boolean) { + let observers = getObservers(fn); + let listeners = getListeners(fn); + + if (observers !== undefined) { + let updateObserver = add ? addObserver : removeObserver; + + for (let i = 0; i < observers.paths.length; i++) { + updateObserver(obj, observers.paths[i], null, key, observers.sync); + } + } + + if (listeners !== undefined) { + let updateListener = add ? addListener : removeListener; + + for (let i = 0; i < listeners.length; i++) { + updateListener(obj, listeners[i], null, key); } } } @@ -420,13 +424,11 @@ function replaceObserversAndListeners( next: Function | null ): void { if (typeof prev === 'function') { - updateObserversAndListeners(obj, key, getObservers(prev), removeObserver); - updateObserversAndListeners(obj, key, getListeners(prev), removeListener); + updateObserversAndListeners(obj, key, prev, false); } if (typeof next === 'function') { - updateObserversAndListeners(obj, key, getObservers(next), addObserver); - updateObserversAndListeners(obj, key, getListeners(next), addListener); + updateObserversAndListeners(obj, key, next, true); } } @@ -845,6 +847,8 @@ if (ALIAS_METHOD) { // OBSERVER HELPER // +type ObserverDefinition = { dependentKeys: string[]; fn: Function; sync: boolean }; + /** Specify a method that observes property changes. @@ -870,24 +874,48 @@ if (ALIAS_METHOD) { @public @static */ -export function observer(...args: (string | Function)[]) { - let func = args.pop(); - let _paths = args; +export function observer(...args: (string | Function)[]): Function; +export function observer(definition: ObserverDefinition): Function; +export function observer(...args: (string | Function | ObserverDefinition)[]) { + let funcOrDef = args.pop(); + + assert( + 'observer must be provided a function or an observer definition', + typeof funcOrDef === 'function' || (typeof funcOrDef === 'object' && funcOrDef !== null) + ); + + let func, dependentKeys, sync; + + if (typeof funcOrDef === 'function') { + func = funcOrDef; + dependentKeys = args; + sync = !ENV._DEFAULT_ASYNC_OBSERVERS; + } else { + func = (funcOrDef as ObserverDefinition).fn; + dependentKeys = (funcOrDef as ObserverDefinition).dependentKeys; + sync = (funcOrDef as ObserverDefinition).sync; + } assert('observer called without a function', typeof func === 'function'); assert( 'observer called without valid path', - _paths.length > 0 && _paths.every(p => typeof p === 'string' && Boolean(p.length)) + Array.isArray(dependentKeys) && + dependentKeys.length > 0 && + dependentKeys.every(p => typeof p === 'string' && Boolean(p.length)) ); + assert('observer called without sync', typeof sync === 'boolean'); let paths: string[] = []; let addWatchedProperty = (path: string) => paths.push(path); - for (let i = 0; i < _paths.length; ++i) { - expandProperties(_paths[i] as string, addWatchedProperty); + for (let i = 0; i < dependentKeys.length; ++i) { + expandProperties(dependentKeys[i] as string, addWatchedProperty); } - setObservers(func as Function, paths); + setObservers(func as Function, { + paths, + sync, + }); return func; } diff --git a/packages/@ember/-internals/metal/lib/observer.ts b/packages/@ember/-internals/metal/lib/observer.ts index def5ed01dee..973ce28eebf 100644 --- a/packages/@ember/-internals/metal/lib/observer.ts +++ b/packages/@ember/-internals/metal/lib/observer.ts @@ -1,3 +1,4 @@ +import { ENV } from '@ember/-internals/environment'; import { peekMeta } from '@ember/-internals/meta'; import { EMBER_METAL_TRACKED_PROPERTIES } from '@ember/canary-features'; import { schedule } from '@ember/runloop'; @@ -12,9 +13,12 @@ interface ActiveObserver { path: string; lastRevision: number; count: number; + suspended: boolean; } -const ACTIVE_OBSERVERS: Map> = new Map(); +const SYNC_DEFAULT = !ENV._DEFAULT_ASYNC_OBSERVERS; +const SYNC_OBSERVERS: Map> = new Map(); +const ASYNC_OBSERVERS: Map> = new Map(); /** @module @ember/object @@ -34,17 +38,18 @@ export function addObserver( obj: any, path: string, target: object | Function | null, - method: string | Function | undefined + method?: string | Function, + sync = SYNC_DEFAULT ): void { let eventName = changeEvent(path); - addListener(obj, eventName, target, method); + addListener(obj, eventName, target, method, false, sync); if (EMBER_METAL_TRACKED_PROPERTIES) { let meta = peekMeta(obj); if (meta === null || !(meta.isPrototypeMeta(obj) || meta.isInitializing())) { - activateObserver(obj, eventName); + activateObserver(obj, eventName, sync); } } else { watch(obj, path); @@ -65,7 +70,8 @@ export function removeObserver( obj: any, path: string, target: object | Function | null, - method: string | Function | undefined + method?: string | Function, + sync = SYNC_DEFAULT ): void { let eventName = changeEvent(path); @@ -73,7 +79,7 @@ export function removeObserver( let meta = peekMeta(obj); if (meta === null || !(meta.isPrototypeMeta(obj) || meta.isInitializing())) { - deactivateObserver(obj, eventName); + deactivateObserver(obj, eventName, sync); } } else { unwatch(obj, path); @@ -82,16 +88,18 @@ export function removeObserver( removeListener(obj, eventName, target, method); } -function getOrCreateActiveObserversFor(target: object) { - if (!ACTIVE_OBSERVERS.has(target)) { - ACTIVE_OBSERVERS.set(target, new Map()); +function getOrCreateActiveObserversFor(target: object, sync: boolean) { + let observerMap = sync === true ? SYNC_OBSERVERS : ASYNC_OBSERVERS; + + if (!observerMap.has(target)) { + observerMap.set(target, new Map()); } - return ACTIVE_OBSERVERS.get(target)!; + return observerMap.get(target)!; } -export function activateObserver(target: object, eventName: string) { - let activeObservers = getOrCreateActiveObserversFor(target); +export function activateObserver(target: object, eventName: string, sync = false) { + let activeObservers = getOrCreateActiveObserversFor(target, sync); if (activeObservers.has(eventName)) { activeObservers.get(eventName)!.count++; @@ -104,12 +112,15 @@ export function activateObserver(target: object, eventName: string) { path, tag, lastRevision: tag.value(), + suspended: false, }); } } -export function deactivateObserver(target: object, eventName: string) { - let activeObservers = ACTIVE_OBSERVERS.get(target); +export function deactivateObserver(target: object, eventName: string, sync = false) { + let observerMap = sync === true ? SYNC_OBSERVERS : ASYNC_OBSERVERS; + + let activeObservers = observerMap.get(target); if (activeObservers !== undefined) { let observer = activeObservers.get(eventName)!; @@ -120,7 +131,7 @@ export function deactivateObserver(target: object, eventName: string) { activeObservers.delete(eventName); if (activeObservers.size === 0) { - ACTIVE_OBSERVERS.delete(target); + observerMap.delete(target); } } } @@ -134,52 +145,91 @@ export function deactivateObserver(target: object, eventName: string) { * @param target */ export function revalidateObservers(target: object) { - if (!ACTIVE_OBSERVERS.has(target)) { - return; + if (ASYNC_OBSERVERS.has(target)) { + ASYNC_OBSERVERS.get(target)!.forEach(observer => { + observer.tag = getChainTagsForKey(target, observer.path); + observer.lastRevision = observer.tag.value(); + }); } - ACTIVE_OBSERVERS.get(target)!.forEach(observer => { - observer.tag = getChainTagsForKey(target, observer.path); - observer.lastRevision = observer.tag.value(); - }); + if (SYNC_OBSERVERS.has(target)) { + SYNC_OBSERVERS.get(target)!.forEach(observer => { + observer.tag = getChainTagsForKey(target, observer.path); + observer.lastRevision = observer.tag.value(); + }); + } } let lastKnownRevision = 0; -export function flushInvalidActiveObservers(shouldSchedule = true) { +export function flushAsyncObservers() { if (lastKnownRevision === CURRENT_TAG.value()) { return; } lastKnownRevision = CURRENT_TAG.value(); - ACTIVE_OBSERVERS.forEach((activeObservers, target) => { + ASYNC_OBSERVERS.forEach((activeObservers, target) => { let meta = peekMeta(target); if (meta && (meta.isSourceDestroying() || meta.isMetaDestroyed())) { - ACTIVE_OBSERVERS.delete(target); + ASYNC_OBSERVERS.delete(target); return; } activeObservers.forEach((observer, eventName) => { if (!observer.tag.validate(observer.lastRevision)) { - let sendObserver = () => { + schedule('actions', () => { try { sendEvent(target, eventName, [target, observer.path]); } finally { observer.tag = getChainTagsForKey(target, observer.path); observer.lastRevision = observer.tag.value(); } - }; - - if (shouldSchedule) { - schedule('actions', sendObserver); - } else { - // TODO: we need to schedule eagerly in exactly one location (_internalReset), - // for query params. We should get rid of this ASAP - sendObserver(); + }); + } + }); + }); +} + +export function flushSyncObservers() { + // When flushing synchronous observers, we know that something has changed (we + // only do this during a notifyPropertyChange), so there's no reason to check + // a global revision. + + SYNC_OBSERVERS.forEach((activeObservers, target) => { + let meta = peekMeta(target); + + if (meta && (meta.isSourceDestroying() || meta.isMetaDestroyed())) { + SYNC_OBSERVERS.delete(target); + return; + } + + activeObservers.forEach((observer, eventName) => { + if (!observer.suspended && !observer.tag.validate(observer.lastRevision)) { + try { + observer.suspended = true; + sendEvent(target, eventName, [target, observer.path]); + } finally { + observer.suspended = false; + observer.tag = getChainTagsForKey(target, observer.path); + observer.lastRevision = observer.tag.value(); } } }); }); } + +export function setObserverSuspended(target: object, property: string, suspended: boolean) { + let activeObservers = SYNC_OBSERVERS.get(target); + + if (!activeObservers) { + return; + } + + let observer = activeObservers.get(changeEvent(property)); + + if (observer) { + observer.suspended = suspended; + } +} diff --git a/packages/@ember/-internals/metal/lib/property_events.ts b/packages/@ember/-internals/metal/lib/property_events.ts index 2d2795776ba..cfe6aaccc48 100644 --- a/packages/@ember/-internals/metal/lib/property_events.ts +++ b/packages/@ember/-internals/metal/lib/property_events.ts @@ -5,6 +5,7 @@ import { DEBUG } from '@glimmer/env'; import changeEvent from './change_event'; import { descriptorForProperty } from './descriptor_map'; import { sendEvent } from './events'; +import { flushSyncObservers } from './observer'; import ObserverSet from './observer_set'; import { markObjectAsDirty } from './tags'; import { assertNotRendered } from './transaction'; @@ -61,6 +62,10 @@ function notifyPropertyChange(obj: object, keyName: string, _meta?: Meta | null) markObjectAsDirty(obj, keyName, meta); } + if (EMBER_METAL_TRACKED_PROPERTIES && deferred <= 0) { + flushSyncObservers(); + } + if (PROPERTY_DID_CHANGE in obj) { obj[PROPERTY_DID_CHANGE](keyName); } @@ -153,7 +158,11 @@ function beginPropertyChanges(): void { function endPropertyChanges(): void { deferred--; if (deferred <= 0) { - observerSet.flush(); + if (EMBER_METAL_TRACKED_PROPERTIES) { + flushSyncObservers(); + } else { + observerSet.flush(); + } } } diff --git a/packages/@ember/-internals/metal/tests/observer_test.js b/packages/@ember/-internals/metal/tests/observer_test.js index 7798dfc5bd5..d83af0d45a5 100644 --- a/packages/@ember/-internals/metal/tests/observer_test.js +++ b/packages/@ember/-internals/metal/tests/observer_test.js @@ -35,7 +35,31 @@ moduleFor( expectAssertion(() => { observer(null); + }, 'observer must be provided a function or an observer definition'); + + expectAssertion(() => { + observer({}); }, 'observer called without a function'); + + expectAssertion(() => { + observer({ + fn() {}, + }); + }, 'observer called without valid path'); + + expectAssertion(() => { + observer({ + fn() {}, + dependentKeys: [], + }); + }, 'observer called without valid path'); + + expectAssertion(() => { + observer({ + fn() {}, + dependentKeys: ['foo'], + }); + }, 'observer called without sync'); } async ['@test observer should fire when property is modified'](assert) { @@ -343,16 +367,12 @@ moduleFor( fooCount++; }); - if (!EMBER_METAL_TRACKED_PROPERTIES) { - beginPropertyChanges(); - } + beginPropertyChanges(); set(obj, 'foo', 'BIFF'); set(obj, 'foo', 'BAZ'); - if (!EMBER_METAL_TRACKED_PROPERTIES) { - endPropertyChanges(); - } + endPropertyChanges(); await runLoopSettled(); diff --git a/packages/@ember/-internals/routing/lib/system/route.ts b/packages/@ember/-internals/routing/lib/system/route.ts index c2fa3e0790f..46a37ed7b75 100644 --- a/packages/@ember/-internals/routing/lib/system/route.ts +++ b/packages/@ember/-internals/routing/lib/system/route.ts @@ -1,7 +1,6 @@ import { computed, defineProperty, - flushInvalidActiveObservers, get, getProperties, isEmpty, @@ -19,7 +18,6 @@ import { } from '@ember/-internals/runtime'; import { EMBER_FRAMEWORK_OBJECT_OWNER_ARGUMENT, - EMBER_METAL_TRACKED_PROPERTIES, EMBER_ROUTING_BUILD_ROUTEINFO_METADATA, } from '@ember/canary-features'; import { assert, deprecate, info, isTesting } from '@ember/debug'; @@ -364,13 +362,6 @@ class Route extends EmberObject implements IRoute { controller._qpDelegate = get(this, '_qp.states.inactive'); this.resetController(controller, isExiting, transition); - - // TODO: Once tags are enabled by default, we should refactor QP changes to - // use autotracking. This will likely be a large refactor, and for now we - // just need to trigger observers eagerly. - if (EMBER_METAL_TRACKED_PROPERTIES) { - flushInvalidActiveObservers(false); - } } /** @@ -954,13 +945,6 @@ class Route extends EmberObject implements IRoute { if (this._environment.options.shouldRender) { this.renderTemplate(controller, context); } - - // TODO: Once tags are enabled by default, we should refactor QP changes to - // use autotracking. This will likely be a large refactor, and for now we - // just need to trigger observers eagerly. - if (EMBER_METAL_TRACKED_PROPERTIES) { - flushInvalidActiveObservers(false); - } } /* diff --git a/packages/@ember/-internals/runtime/lib/system/core_object.js b/packages/@ember/-internals/runtime/lib/system/core_object.js index 1b1fb7ab1d6..8cc88131219 100644 --- a/packages/@ember/-internals/runtime/lib/system/core_object.js +++ b/packages/@ember/-internals/runtime/lib/system/core_object.js @@ -145,7 +145,7 @@ function initialize(obj, properties) { if (observerEvents !== undefined) { for (let i = 0; i < observerEvents.length; i++) { - activateObserver(obj, observerEvents[i]); + activateObserver(obj, observerEvents[i].event, observerEvents[i].sync); } } } else { diff --git a/packages/@ember/-internals/runtime/tests/system/array_proxy/length_test.js b/packages/@ember/-internals/runtime/tests/system/array_proxy/length_test.js index 8218074dab7..e7314eb0ce9 100644 --- a/packages/@ember/-internals/runtime/tests/system/array_proxy/length_test.js +++ b/packages/@ember/-internals/runtime/tests/system/array_proxy/length_test.js @@ -168,6 +168,9 @@ moduleFor( e: observer('colors.content.[]', () => eCalled++), }).create(); + // bootstrap aliases + obj.length; + obj.set( 'model', ArrayProxy.create({ @@ -175,9 +178,6 @@ moduleFor( }) ); - // bootstrap aliases - obj.length; - await runLoopSettled(); assert.equal(obj.get('colors.content.length'), 3); diff --git a/packages/@ember/-internals/utils/lib/super.ts b/packages/@ember/-internals/utils/lib/super.ts index 9e45afb55af..c143420c116 100644 --- a/packages/@ember/-internals/utils/lib/super.ts +++ b/packages/@ember/-internals/utils/lib/super.ts @@ -38,10 +38,8 @@ function hasSuper(func: Function) { const OBSERVERS_MAP = new WeakMap(); -export function setObservers(func: Function, observers?: string[]) { - if (observers) { - OBSERVERS_MAP.set(func, observers); - } +export function setObservers(func: Function, observers: { paths: string[]; sync: boolean }) { + OBSERVERS_MAP.set(func, observers); } export function getObservers(func: Function) { diff --git a/packages/@ember/runloop/index.js b/packages/@ember/runloop/index.js index d65e42ade90..78071ac120a 100644 --- a/packages/@ember/runloop/index.js +++ b/packages/@ember/runloop/index.js @@ -1,6 +1,6 @@ import { assert } from '@ember/debug'; import { onErrorTarget } from '@ember/-internals/error-handling'; -import { flushInvalidActiveObservers } from '@ember/-internals/metal'; +import { flushAsyncObservers } from '@ember/-internals/metal'; import Backburner from 'backburner'; import { EMBER_METAL_TRACKED_PROPERTIES } from '@ember/canary-features'; @@ -17,7 +17,7 @@ function onEnd(current, next) { currentRunLoop = next; if (EMBER_METAL_TRACKED_PROPERTIES) { - flushInvalidActiveObservers(); + flushAsyncObservers(); } } @@ -26,7 +26,7 @@ let flush; if (EMBER_METAL_TRACKED_PROPERTIES) { flush = function(queueName, next) { if (queueName === 'render' || queueName === _rsvpErrorQueue) { - flushInvalidActiveObservers(); + flushAsyncObservers(); } next(); diff --git a/tests/docs/expected.js b/tests/docs/expected.js index bf658c30c21..2575a1b2dd7 100644 --- a/tests/docs/expected.js +++ b/tests/docs/expected.js @@ -10,6 +10,7 @@ module.exports = { '[]', '_APPLICATION_TEMPLATE_WRAPPER', '_JQUERY_INTEGRATION', + '_DEFAULT_ASYNC_OBSERVERS', '_RERENDER_LOOP_LIMIT', '_TEMPLATE_ONLY_GLIMMER_COMPONENTS', 'Input',