Skip to content

Commit d43b77c

Browse files
committed
feat: add options debounceWait
1 parent 54ea6c6 commit d43b77c

File tree

8 files changed

+69
-13
lines changed

8 files changed

+69
-13
lines changed

src/client/update.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { rootConfigKey } from '../shared/constants'
33
// store an id to keep track of DOM updates
44
let batchId = null
55

6-
export function triggerUpdate (rootVm, hookName) {
6+
export function triggerUpdate ({ debounceWait }, rootVm, hookName) {
77
// if an update was triggered during initialization or when an update was triggered by the
88
// metaInfo watcher, set initialized to null
99
// then we keep falsy value but know we need to run a triggerUpdate after initialization
@@ -13,7 +13,7 @@ export function triggerUpdate (rootVm, hookName) {
1313

1414
if (rootVm[rootConfigKey].initialized && !rootVm[rootConfigKey].pausing) {
1515
// batch potential DOM updates to prevent extraneous re-rendering
16-
batchUpdate(() => rootVm.$meta().refresh())
16+
batchUpdate(() => void rootVm.$meta().refresh(), debounceWait)
1717
}
1818
}
1919

@@ -25,10 +25,14 @@ export function triggerUpdate (rootVm, hookName) {
2525
* @return {Number} id - a new ID
2626
*/
2727
export function batchUpdate (callback, timeout) {
28-
timeout = timeout || 10
28+
timeout = timeout === undefined ? 10 : timeout
2929

30-
clearTimeout(batchId)
30+
if (!timeout) {
31+
callback()
32+
return
33+
}
3134

35+
clearTimeout(batchId)
3236
batchId = setTimeout(() => {
3337
callback()
3438
}, timeout)

src/shared/$meta.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ export default function $meta (options) {
2323
options.refreshOnceOnNavigation = newOptions[refreshNavKey]
2424
addNavGuards($root)
2525
}
26+
27+
const debounceWaitKey = 'debounceWait'
28+
if (newOptions && newOptions[debounceWaitKey]) {
29+
const debounceWait = parseInt(newOptions[debounceWaitKey])
30+
if (!isNaN(debounceWait)) {
31+
options.debounceWait = debounceWait
32+
}
33+
}
2634
},
2735
'refresh': () => refresh($root, options),
2836
'inject': () => process.server ? inject($root, options) : showWarningNotSupportedInBrowserBundle('inject'),

src/shared/constants.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,17 @@ export const contentKeyName = 'content'
4949
// The id used for the ssr app
5050
export const ssrAppId = 'ssr'
5151

52+
// How long meta update
53+
export const debounceWait = 10
54+
5255
export const defaultOptions = {
5356
keyName,
5457
attribute,
5558
ssrAttribute,
5659
tagIDKeyName,
5760
contentKeyName,
5861
metaTemplateKeyName,
62+
debounceWait,
5963
ssrAppId
6064
}
6165

src/shared/mixin.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export default function createMixin (Vue, options) {
6969
// credit for this suggestion goes to [Sébastien Chopin](https://github.com/Atinux)
7070
ensuredPush($options, 'created', function () {
7171
this.$watch('$metaInfo', function () {
72-
triggerUpdate(this[rootKey], 'watcher')
72+
triggerUpdate(options, this[rootKey], 'watcher')
7373
})
7474
})
7575
}
@@ -112,7 +112,7 @@ export default function createMixin (Vue, options) {
112112
// current hook was called
113113
// (during initialization all changes are blocked)
114114
if (tags === false && $root[rootConfigKey].initialized === null) {
115-
this.$nextTick(() => triggerUpdate($root, 'init'))
115+
this.$nextTick(() => triggerUpdate(options, $root, 'init'))
116116
}
117117

118118
$root[rootConfigKey].initialized = true
@@ -126,7 +126,6 @@ export default function createMixin (Vue, options) {
126126
})
127127
}
128128
})
129-
130129
// add the navigation guards if requested
131130
if (options.refreshOnceOnNavigation) {
132131
addNavGuards($root)
@@ -142,7 +141,7 @@ export default function createMixin (Vue, options) {
142141
// no need to add this hooks on server side
143142
updateOnLifecycleHook.forEach((lifecycleHook) => {
144143
ensuredPush($options, lifecycleHook, function () {
145-
triggerUpdate(this[rootKey], lifecycleHook)
144+
triggerUpdate(options, this[rootKey], lifecycleHook)
146145
})
147146
})
148147
},
@@ -165,7 +164,7 @@ export default function createMixin (Vue, options) {
165164

166165
clearInterval(interval)
167166

168-
triggerUpdate($this.$root, 'destroyed')
167+
triggerUpdate(options, $this.$root, 'destroyed')
169168
}, 50)
170169
}
171170
}

src/shared/options.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export function setOptions (options) {
1717
tagIDKeyName: options['tagIDKeyName'] || defaultOptions.tagIDKeyName,
1818
contentKeyName: options['contentKeyName'] || defaultOptions.contentKeyName,
1919
metaTemplateKeyName: options['metaTemplateKeyName'] || defaultOptions.metaTemplateKeyName,
20+
debounceWait: options['debounceWait'] || defaultOptions.debounceWait,
2021
ssrAppId: options['ssrAppId'] || defaultOptions.ssrAppId,
2122
refreshOnceOnNavigation: !!options['refreshOnceOnNavigation']
2223
}

test/unit/components.test.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ describe('components', () => {
479479
wrapper.destroy()
480480
})
481481

482-
test('can toggle refreshOnceOnNavigation runtime', () => {
482+
test('can enable option refreshOnceOnNavigation runtime', () => {
483483
const guards = {}
484484
const wrapper = mount(HelloWorld, {
485485
localVue: Vue,
@@ -503,4 +503,14 @@ describe('components', () => {
503503
expect(guards.before).not.toBeUndefined()
504504
expect(guards.after).not.toBeUndefined()
505505
})
506+
507+
test('can set option debounceWait runtime', () => {
508+
const wrapper = mount(HelloWorld, { localVue: Vue })
509+
510+
expect(wrapper.vm.$meta().getOptions().debounceWait).toBe(10)
511+
512+
wrapper.vm.$meta().setOptions({ debounceWait: 69420 })
513+
514+
expect(wrapper.vm.$meta().getOptions().debounceWait).toBe(69420)
515+
})
506516
})

test/unit/plugin.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ describe('plugin', () => {
153153
const batchUpdateSpy = batchUpdate.mockImplementation(_batchUpdate)
154154
// because triggerUpdate & batchUpdate reside in the same file we cant mock them both,
155155
// so just recreate the triggerUpdate fn by copying its implementation
156-
const triggerUpdateSpy = triggerUpdate.mockImplementation((vm, hookName) => {
156+
const triggerUpdateSpy = triggerUpdate.mockImplementation((options, vm, hookName) => {
157157
if (vm.$root._vueMeta.initialized && !vm.$root._vueMeta.pausing) {
158158
// batch potential DOM updates to prevent extraneous re-rendering
159159
batchUpdateSpy(() => vm.$meta().refresh())
@@ -216,15 +216,15 @@ describe('plugin', () => {
216216
expect(metaInfo.title).toBe(title)
217217
})
218218

219-
test('updates are batched', async () => {
219+
test('updates are batched by default', async () => {
220220
jest.useFakeTimers()
221221

222222
const { batchUpdate: _batchUpdate } = jest.requireActual('../../src/client/update')
223223
const batchUpdateSpy = batchUpdate.mockImplementation(_batchUpdate)
224224
const refreshSpy = jest.fn()
225225
// because triggerUpdate & batchUpdate reside in the same file we cant mock them both,
226226
// so just recreate the triggerUpdate fn by copying its implementation
227-
triggerUpdate.mockImplementation((vm, hookName) => {
227+
triggerUpdate.mockImplementation((options, vm, hookName) => {
228228
if (vm.$root._vueMeta.initialized && !vm.$root._vueMeta.pausing) {
229229
// batch potential DOM updates to prevent extraneous re-rendering
230230
batchUpdateSpy(refreshSpy)

test/unit/shared.test.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { setOptions } from '../../src/shared/options'
22
import { defaultOptions } from '../../src/shared/constants'
3+
import { triggerUpdate } from '../../src/client/update'
34

45
describe('shared', () => {
56
test('can use setOptions', () => {
@@ -11,4 +12,33 @@ describe('shared', () => {
1112
expect(options.contentKeyName).toBeDefined()
1213
expect(options.contentKeyName).toBe(defaultOptions.contentKeyName)
1314
})
15+
16+
test('options.debounceWait is used', () => {
17+
jest.useFakeTimers()
18+
19+
const refresh = jest.fn()
20+
const componentMock = {
21+
_vueMeta: {
22+
initialized: true,
23+
pausing: false
24+
},
25+
$meta: () => ({ refresh })
26+
}
27+
28+
triggerUpdate({ debounceWait: 0 }, componentMock, 'test')
29+
30+
expect(refresh).toHaveBeenCalledTimes(1)
31+
32+
triggerUpdate({}, componentMock, 'test')
33+
expect(refresh).toHaveBeenCalledTimes(1)
34+
jest.advanceTimersByTime(11)
35+
expect(refresh).toHaveBeenCalledTimes(2)
36+
37+
triggerUpdate({ debounceWait: 69420 }, componentMock, 'test')
38+
expect(refresh).toHaveBeenCalledTimes(2)
39+
jest.advanceTimersByTime(11)
40+
expect(refresh).toHaveBeenCalledTimes(2)
41+
jest.advanceTimersByTime(69500)
42+
expect(refresh).toHaveBeenCalledTimes(3)
43+
})
1444
})

0 commit comments

Comments
 (0)