From ea6124ee917a1040453551538e1691799032e858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B9=94=E5=81=A5?= Date: Thu, 13 Sep 2018 10:56:48 +0800 Subject: [PATCH 1/4] Add $refreshAsyncComputed function. --- README.md | 25 +++++++++++++++++++++++++ src/index.js | 19 ++++++++++++++++++- test/index.js | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a2030cc..3b35a46 100644 --- a/README.md +++ b/README.md @@ -322,6 +322,31 @@ new Vue({ } } ``` +## Manually Refreshed + +Sometimes, we should refresh properties manually to sync data from server side. +Using `$refreshAsyncComputed(propName)` to refresh manually and get promise for refreshing. + +For example: +```js +new Vue({ + asyncComputed: { + articleList() { + return Vue.http.get('/article/list') + } + }, + methods: { + newArticle() { + Vue.http.post('/article/new', { + title: 'New Article', + content: 'Hello world' + }) + .then(() => this.$refreshAsyncComputed('articleList')) + .then(() => console.log('done')) + } + } +}) +``` ## Error handling diff --git a/src/index.js b/src/index.js index 13d5141..8056ace 100644 --- a/src/index.js +++ b/src/index.js @@ -18,6 +18,8 @@ const AsyncComputed = { .optionMergeStrategies .asyncComputed = Vue.config.optionMergeStrategies.computed + Vue.prototype.$refreshAsyncComputed = $refreshAsyncComputed + Vue.mixin({ beforeCreate () { const optionData = this.$options.data @@ -88,7 +90,7 @@ const AsyncComputed = { handler(err.stack) } }) - }, { immediate: true }) + }, {immediate: true}) } } }) @@ -147,6 +149,21 @@ function generateDefault (fn, pluginOptions) { } } +function $refreshAsyncComputed (propName) { + const promisePropName = prefix + propName + if (this.hasOwnProperty(propName) && this._computedWatchers && this._computedWatchers[promisePropName]) { + this._computedWatchers[promisePropName].evaluate() + const [watcher] = this._watchers.filter(watcher => watcher.expression === promisePropName) + const promise = this[promisePropName] + return promise.then(() => { + watcher.run() + return promise + }) + } else { + throw new Error('Can not find async computed property ' + JSON.stringify(propName)) + } +} + export default AsyncComputed /* istanbul ignore if */ diff --git a/test/index.js b/test/index.js index cd9e578..c60c6f7 100644 --- a/test/index.js +++ b/test/index.js @@ -716,3 +716,42 @@ test("shouldUpdate works with lazy", t => { }) }) }) + +test('$refreshAsyncComputed works', t => { + t.plan(7) + + let countA = 1 + let countB = 1 + + const vm = new Vue({ + asyncComputed: { + async_a () { return new Promise(resolve => setTimeout(() => resolve(countA++), 6)) }, + lazy_async_b: { + lazy: true, + get () { return new Promise(resolve => setTimeout(() => resolve(countB++), 6)) }, + } + } + }) + + t.equal(vm.async_a, null) + setTimeout(() => { + t.equal(vm.async_a, 1) + // eslint-disable-next-line promise/catch-or-return + vm.$refreshAsyncComputed('async_a').then(() => t.equal(vm.async_a, 2)) + }, 12) + + setTimeout(() => { + t.equal(vm.lazy_async_b, null) + setTimeout(() => { + t.equal(vm.lazy_async_b, 1) + // eslint-disable-next-line promise/catch-or-return + vm.$refreshAsyncComputed('lazy_async_b').then(() => t.equal(vm.lazy_async_b, 2)) + }, 12) + }, 12) + + try { + vm.$refreshAsyncComputed('wrong_property') + } catch (err) { + t.equal(err.message, 'Can not find async computed property ' + JSON.stringify('wrong_property')) + } +}) From eb70ccc6b1ee21934cf9850b9def7d7203837a28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B9=94=E5=81=A5?= Date: Thu, 13 Sep 2018 13:01:21 +0800 Subject: [PATCH 2/4] Fixed bug --- src/index.js | 30 ++++++++++++++++++------------ test/index.js | 1 + 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/index.js b/src/index.js index 8056ace..2d53bb4 100644 --- a/src/index.js +++ b/src/index.js @@ -30,6 +30,8 @@ const AsyncComputed = { this.$options.computed[prefix + key] = getterFn(key, this.$options.asyncComputed[key]) } + this._asyncComputedWatcher = {} + this.$options.data = function vueAsyncComputedInjectedDataFn () { const data = ( (typeof optionData === 'function') @@ -61,7 +63,8 @@ const AsyncComputed = { for (const key in this.$options.asyncComputed || {}) { let promiseId = 0 - this.$watch(prefix + key, newPromise => { + + const watcher = newPromise => { const thisPromise = ++promiseId if (newPromise === DidNotUpdate) { @@ -90,7 +93,10 @@ const AsyncComputed = { handler(err.stack) } }) - }, {immediate: true}) + } + + this.$watch(prefix + key, watcher, {immediate: true}) + this._asyncComputedWatcher[key] = watcher } } }) @@ -149,18 +155,18 @@ function generateDefault (fn, pluginOptions) { } } -function $refreshAsyncComputed (propName) { - const promisePropName = prefix + propName - if (this.hasOwnProperty(propName) && this._computedWatchers && this._computedWatchers[promisePropName]) { - this._computedWatchers[promisePropName].evaluate() - const [watcher] = this._watchers.filter(watcher => watcher.expression === promisePropName) - const promise = this[promisePropName] - return promise.then(() => { - watcher.run() - return promise +function $refreshAsyncComputed (key) { + const prefixedKey = prefix + key + if (this.hasOwnProperty(key) && this.hasOwnProperty(prefixedKey) && this._asyncComputedWatcher[key]) { + this._computedWatchers[prefixedKey].evaluate() + const watcher = this._asyncComputedWatcher[key] + const newPromise = this[prefixedKey] + return newPromise.then(() => { + watcher.apply(this, [newPromise]) + return newPromise }) } else { - throw new Error('Can not find async computed property ' + JSON.stringify(propName)) + throw new Error('Can not find async computed property ' + JSON.stringify(key)) } } diff --git a/test/index.js b/test/index.js index c60c6f7..ff44088 100644 --- a/test/index.js +++ b/test/index.js @@ -11,6 +11,7 @@ const pluginOptions = { } Vue.use(AsyncComputed, pluginOptions) +process.NODE_ENV = 'production' test("Async computed values are computed", t => { t.plan(4) From aca273e2aa92058340346773ddfa054bbe636829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B9=94=E5=81=A5?= Date: Thu, 13 Sep 2018 13:08:18 +0800 Subject: [PATCH 3/4] Rename `refresh` to `update` --- README.md | 8 ++++---- src/index.js | 4 ++-- test/index.js | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 3b35a46..831bcb1 100644 --- a/README.md +++ b/README.md @@ -322,10 +322,10 @@ new Vue({ } } ``` -## Manually Refreshed +## Manually updated -Sometimes, we should refresh properties manually to sync data from server side. -Using `$refreshAsyncComputed(propName)` to refresh manually and get promise for refreshing. +Sometimes, we should update properties manually to sync data from server side. +Using `$updateAsyncComputed(key)` to update manually and get promise for updating. For example: ```js @@ -341,7 +341,7 @@ new Vue({ title: 'New Article', content: 'Hello world' }) - .then(() => this.$refreshAsyncComputed('articleList')) + .then(() => this.$updateAsyncComputed('articleList')) .then(() => console.log('done')) } } diff --git a/src/index.js b/src/index.js index 2d53bb4..e22dbc2 100644 --- a/src/index.js +++ b/src/index.js @@ -18,7 +18,7 @@ const AsyncComputed = { .optionMergeStrategies .asyncComputed = Vue.config.optionMergeStrategies.computed - Vue.prototype.$refreshAsyncComputed = $refreshAsyncComputed + Vue.prototype.$updateAsyncComputed = $updateAsyncComputed Vue.mixin({ beforeCreate () { @@ -155,7 +155,7 @@ function generateDefault (fn, pluginOptions) { } } -function $refreshAsyncComputed (key) { +function $updateAsyncComputed (key) { const prefixedKey = prefix + key if (this.hasOwnProperty(key) && this.hasOwnProperty(prefixedKey) && this._asyncComputedWatcher[key]) { this._computedWatchers[prefixedKey].evaluate() diff --git a/test/index.js b/test/index.js index ff44088..bc3c090 100644 --- a/test/index.js +++ b/test/index.js @@ -718,7 +718,7 @@ test("shouldUpdate works with lazy", t => { }) }) -test('$refreshAsyncComputed works', t => { +test('$updateAsyncComputed works', t => { t.plan(7) let countA = 1 @@ -738,7 +738,7 @@ test('$refreshAsyncComputed works', t => { setTimeout(() => { t.equal(vm.async_a, 1) // eslint-disable-next-line promise/catch-or-return - vm.$refreshAsyncComputed('async_a').then(() => t.equal(vm.async_a, 2)) + vm.$updateAsyncComputed('async_a').then(() => t.equal(vm.async_a, 2)) }, 12) setTimeout(() => { @@ -746,12 +746,12 @@ test('$refreshAsyncComputed works', t => { setTimeout(() => { t.equal(vm.lazy_async_b, 1) // eslint-disable-next-line promise/catch-or-return - vm.$refreshAsyncComputed('lazy_async_b').then(() => t.equal(vm.lazy_async_b, 2)) + vm.$updateAsyncComputed('lazy_async_b').then(() => t.equal(vm.lazy_async_b, 2)) }, 12) }, 12) try { - vm.$refreshAsyncComputed('wrong_property') + vm.$updateAsyncComputed('wrong_property') } catch (err) { t.equal(err.message, 'Can not find async computed property ' + JSON.stringify('wrong_property')) } From 808391e15bec3a9e7c25773c20447af1eaae6cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B9=94=E5=81=A5?= Date: Thu, 13 Sep 2018 13:17:03 +0800 Subject: [PATCH 4/4] Remove useless code --- test/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/index.js b/test/index.js index bc3c090..9e3fdd3 100644 --- a/test/index.js +++ b/test/index.js @@ -11,7 +11,6 @@ const pluginOptions = { } Vue.use(AsyncComputed, pluginOptions) -process.NODE_ENV = 'production' test("Async computed values are computed", t => { t.plan(4)