From 8eee446dcf47440b729a4c3bbb4f8242f0e7040e Mon Sep 17 00:00:00 2001 From: eddyerburgh Date: Sun, 20 May 2018 06:40:54 +0100 Subject: [PATCH 1/7] feat: add async option --- src/core/observer/scheduler.js | 4 ++- test/unit/features/global-api/config.spec.js | 27 ++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/core/observer/scheduler.js b/src/core/observer/scheduler.js index e7ccf57dd25..903e9584332 100644 --- a/src/core/observer/scheduler.js +++ b/src/core/observer/scheduler.js @@ -145,7 +145,9 @@ export function queueWatcher (watcher: Watcher) { // queue the flush if (!waiting) { waiting = true - nextTick(flushSchedulerQueue) + config.async + ? nextTick(flushSchedulerQueue) + : flushSchedulerQueue() } } } diff --git a/test/unit/features/global-api/config.spec.js b/test/unit/features/global-api/config.spec.js index 1edfc3c7829..fdb26c442ee 100644 --- a/test/unit/features/global-api/config.spec.js +++ b/test/unit/features/global-api/config.spec.js @@ -55,4 +55,31 @@ describe('Global config', () => { Vue.config.ignoredElements = [] }) }) + + describe('async', () => { + it('does not update synchronously when false', () => { + const spy = jasmine.createSpy() + Vue.config.async = true + const vm = new Vue({ + template: `
`, + updated: spy, + data: { value: true } + }).$mount() + vm.value = false + expect(spy).not.toHaveBeenCalled() + }) + + it('updates synchronously when false', () => { + const spy = jasmine.createSpy() + Vue.config.async = false + const vm = new Vue({ + template: `
`, + updated: spy, + data: { value: true } + }).$mount() + vm.value = false + expect(spy).toHaveBeenCalled() + Vue.config.async = true + }) + }) }) From bb2e69b20986245ed091dea6faa80737438599e9 Mon Sep 17 00:00:00 2001 From: eddyerburgh Date: Sun, 20 May 2018 06:57:03 +0100 Subject: [PATCH 2/7] feat: add async to config --- src/core/config.js | 9 +++++++++ test/unit/features/global-api/config.spec.js | 3 +-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/core/config.js b/src/core/config.js index f25f09d1f35..a115c45e740 100644 --- a/src/core/config.js +++ b/src/core/config.js @@ -28,6 +28,9 @@ export type Config = { getTagNamespace: (x?: string) => string | void; mustUseProp: (tag: string, type: ?string, name: string) => boolean; + // private + async: boolean; + // legacy _lifecycleHooks: Array; }; @@ -114,6 +117,12 @@ export default ({ */ mustUseProp: no, + /** + * Perform updates asynchronously. This should never be set to false in + * production as it will significantly reduce performance. + */ + async: true, + /** * Exposed for legacy reasons */ diff --git a/test/unit/features/global-api/config.spec.js b/test/unit/features/global-api/config.spec.js index fdb26c442ee..31ac384f434 100644 --- a/test/unit/features/global-api/config.spec.js +++ b/test/unit/features/global-api/config.spec.js @@ -57,9 +57,8 @@ describe('Global config', () => { }) describe('async', () => { - it('does not update synchronously when false', () => { + it('does not update synchronously when true', () => { const spy = jasmine.createSpy() - Vue.config.async = true const vm = new Vue({ template: `
`, updated: spy, From 46574bc0665a457ee6ce6d6f1dcfd78709a8f6c7 Mon Sep 17 00:00:00 2001 From: eddyerburgh Date: Sun, 20 May 2018 07:07:12 +0100 Subject: [PATCH 3/7] feat: add async to types --- types/test/vue-test.ts | 1 + types/vue.d.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/types/test/vue-test.ts b/types/test/vue-test.ts index 96949371793..326969c1637 100644 --- a/types/test/vue-test.ts +++ b/types/test/vue-test.ts @@ -73,6 +73,7 @@ class Test extends Vue { }; config.keyCodes = { esc: 27 }; config.ignoredElements = ['foo', /^ion-/]; + config.async = false } static testMethods() { diff --git a/types/vue.d.ts b/types/vue.d.ts index e0b29157cfa..179fb5fe38e 100644 --- a/types/vue.d.ts +++ b/types/vue.d.ts @@ -74,6 +74,7 @@ export interface VueConfiguration { warnHandler(msg: string, vm: Vue, trace: string): void; ignoredElements: (string | RegExp)[]; keyCodes: { [key: string]: number | number[] }; + async: boolean; } export interface VueConstructor { From dfdedad5b51a6965e0981fda75f6ad6cdcce36e7 Mon Sep 17 00:00:00 2001 From: eddyerburgh Date: Thu, 24 May 2018 19:32:39 +0100 Subject: [PATCH 4/7] refactor: add production check --- src/core/observer/scheduler.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/core/observer/scheduler.js b/src/core/observer/scheduler.js index 903e9584332..0832a67c78e 100644 --- a/src/core/observer/scheduler.js +++ b/src/core/observer/scheduler.js @@ -145,9 +145,12 @@ export function queueWatcher (watcher: Watcher) { // queue the flush if (!waiting) { waiting = true - config.async - ? nextTick(flushSchedulerQueue) - : flushSchedulerQueue() + + if (process.env.NODE_ENV !== 'production' && config.async) { + flushSchedulerQueue() + return + } + nextTick(flushSchedulerQueue) } } } From f6ec0b6302bb0a3a4db124bacf2bd2d8c4f04d50 Mon Sep 17 00:00:00 2001 From: eddyerburgh Date: Thu, 24 May 2018 20:36:30 +0100 Subject: [PATCH 5/7] fix: add correct condition --- src/core/observer/scheduler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/observer/scheduler.js b/src/core/observer/scheduler.js index 0832a67c78e..176ee2c36f7 100644 --- a/src/core/observer/scheduler.js +++ b/src/core/observer/scheduler.js @@ -146,7 +146,7 @@ export function queueWatcher (watcher: Watcher) { if (!waiting) { waiting = true - if (process.env.NODE_ENV !== 'production' && config.async) { + if (process.env.NODE_ENV !== 'production' && !config.async) { flushSchedulerQueue() return } From b01d0404cc4ca8fb39ff992ed1126406763dd699 Mon Sep 17 00:00:00 2001 From: eddyerburgh Date: Sat, 21 Jul 2018 19:20:39 +0100 Subject: [PATCH 6/7] fix: sort subs --- src/core/observer/dep.js | 7 ++++ test/unit/features/global-api/config.spec.js | 41 ++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/core/observer/dep.js b/src/core/observer/dep.js index abf3b275ce4..1dd37783490 100644 --- a/src/core/observer/dep.js +++ b/src/core/observer/dep.js @@ -2,6 +2,7 @@ import type Watcher from './watcher' import { remove } from '../util/index' +import config from '../config' let uid = 0 @@ -36,6 +37,12 @@ export default class Dep { notify () { // stabilize the subscriber list first const subs = this.subs.slice() + if (process.env.NODE_ENV !== 'production' && !config.async) { + // subs aren't sorted in scheduler if not running async + // we need to sort them now to make sure they fire in correct + // order + subs.sort((a, b) => a.id - b.id) + } for (let i = 0, l = subs.length; i < l; i++) { subs[i].update() } diff --git a/test/unit/features/global-api/config.spec.js b/test/unit/features/global-api/config.spec.js index 31ac384f434..f2e5074ce72 100644 --- a/test/unit/features/global-api/config.spec.js +++ b/test/unit/features/global-api/config.spec.js @@ -80,5 +80,46 @@ describe('Global config', () => { expect(spy).toHaveBeenCalled() Vue.config.async = true }) + + it('runs watchers in correct order when false', () => { + Vue.config.async = false + const vm = new Vue({ + template: ` +
+ {{ computed }} +
`, + props: ['prop'], + propsData: { + 'prop': [] + }, + data: () => ({ + data: '' + }), + computed: { + computed () { + return this.prop.join(',') + } + }, + watch: { + prop: 'execute' + }, + methods: { + execute () { + this.data = this.computed + } + } + }).$mount() + expect(vm.computed).toBe('') + expect(vm.data).toBe('') + + vm.prop = [1, 2, 3] + expect(vm.computed).toBe('1,2,3') + expect(vm.data).toBe('1,2,3') + + vm.prop.push(4, 5) + expect(vm.computed).toBe('1,2,3,4,5') + expect(vm.data).toBe('1,2,3,4,5') + Vue.config.async = true + }) }) }) From e3eef459d1575d14cfa0aaa546ebf60d18f6da09 Mon Sep 17 00:00:00 2001 From: eddyerburgh Date: Sun, 22 Jul 2018 09:19:07 +0100 Subject: [PATCH 7/7] refactor: reword comment --- src/core/config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/config.js b/src/core/config.js index a115c45e740..cae9d3dd395 100644 --- a/src/core/config.js +++ b/src/core/config.js @@ -118,8 +118,8 @@ export default ({ mustUseProp: no, /** - * Perform updates asynchronously. This should never be set to false in - * production as it will significantly reduce performance. + * Perform updates asynchronously. Intended to be used by Vue Test Utils + * This will significantly reduce performance if set to false. */ async: true,