Skip to content

Commit cd45369

Browse files
committed
Add status property.
1 parent 0fc27db commit cd45369

File tree

2 files changed

+127
-5
lines changed

2 files changed

+127
-5
lines changed

src/index.js

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,16 @@ const AsyncComputed = {
2121
Vue.mixin({
2222
beforeCreate () {
2323
const optionData = this.$options.data
24+
const asyncComputed = this.$options.asyncComputed || {}
25+
this.$asyncComputed = {}
26+
27+
if (!Object.keys(asyncComputed).length) return
2428

2529
if (!this.$options.computed) this.$options.computed = {}
2630

27-
for (const key in this.$options.asyncComputed || {}) {
28-
this.$options.computed[prefix + key] = getterFn(key, this.$options.asyncComputed[key])
31+
for (const key in asyncComputed) {
32+
const getter = getterFn(key, this.$options.asyncComputed[key])
33+
this.$options.computed[prefix + key] = getter
2934
}
3035

3136
this.$options.data = function vueAsyncComputedInjectedDataFn () {
@@ -34,7 +39,7 @@ const AsyncComputed = {
3439
? optionData.call(this)
3540
: optionData
3641
) || {}
37-
for (const key in this.$options.asyncComputed || {}) {
42+
for (const key in asyncComputed) {
3843
const item = this.$options.asyncComputed[key]
3944
if (isComputedLazy(item)) {
4045
initLazy(data, key)
@@ -59,7 +64,7 @@ const AsyncComputed = {
5964

6065
for (const key in this.$options.asyncComputed || {}) {
6166
let promiseId = 0
62-
this.$watch(prefix + key, newPromise => {
67+
const watcher = newPromise => {
6368
const thisPromise = ++promiseId
6469

6570
if (newPromise === DidNotUpdate) {
@@ -69,13 +74,17 @@ const AsyncComputed = {
6974
if (!newPromise || !newPromise.then) {
7075
newPromise = Promise.resolve(newPromise)
7176
}
77+
setAsyncState(this.$asyncComputed[key], 'updating')
7278

7379
newPromise.then(value => {
7480
if (thisPromise !== promiseId) return
81+
setAsyncState(this.$asyncComputed[key], 'success')
7582
this[key] = value
7683
}).catch(err => {
7784
if (thisPromise !== promiseId) return
7885

86+
setAsyncState(this.$asyncComputed[key], 'error')
87+
this.$asyncComputed[key].exception = err
7988
if (pluginOptions.errorHandler === false) return
8089

8190
const handler = (pluginOptions.errorHandler === undefined)
@@ -88,13 +97,34 @@ const AsyncComputed = {
8897
handler(err.stack)
8998
}
9099
})
91-
}, { immediate: true })
100+
}
101+
this.$asyncComputed[key] = {
102+
exception: null,
103+
update: () => {
104+
watcher(getterOnly(this.$options.asyncComputed[key])())
105+
}
106+
}
107+
setAsyncState(this.$asyncComputed[key], 'updating')
108+
this.$watch(prefix + key, watcher, { immediate: true })
92109
}
93110
}
94111
})
95112
}
96113
}
97114

115+
function setAsyncState (stateObject, state) {
116+
stateObject.state = state
117+
stateObject.updating = state === 'updating'
118+
stateObject.error = state === 'error'
119+
stateObject.success = state === 'success'
120+
}
121+
122+
function getterOnly (fn) {
123+
if (typeof fn === 'function') return fn
124+
125+
return fn.get
126+
}
127+
98128
function getterFn (key, fn) {
99129
if (typeof fn === 'function') return fn
100130

test/index.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,3 +716,95 @@ test("shouldUpdate works with lazy", t => {
716716
})
717717
})
718718
})
719+
720+
test("$asyncComputed is empty if there are no async computed properties", t => {
721+
t.plan(1)
722+
const vm = new Vue({
723+
})
724+
t.deepEqual(vm.$asyncComputed, {})
725+
})
726+
727+
test("$asyncComputed[name] is created for all async computed properties", t => {
728+
t.plan(15)
729+
const vm = new Vue({
730+
asyncComputed: {
731+
a () {
732+
return Promise.resolve(1)
733+
},
734+
b () {
735+
return Promise.resolve(2)
736+
}
737+
}
738+
})
739+
t.deepEqual(Object.keys(vm.$asyncComputed), ['a', 'b'])
740+
t.equal(vm.$asyncComputed['a'].state, 'updating')
741+
t.equal(vm.$asyncComputed['b'].state, 'updating')
742+
t.equal(vm.$asyncComputed['a'].updating, true)
743+
t.equal(vm.$asyncComputed['a'].success, false)
744+
t.equal(vm.$asyncComputed['a'].error, false)
745+
t.equal(vm.$asyncComputed['a'].exception, null)
746+
747+
Vue.nextTick(() => {
748+
t.equal(vm.a, 1)
749+
t.equal(vm.b, 2)
750+
t.equal(vm.$asyncComputed['a'].state, 'success')
751+
t.equal(vm.$asyncComputed['b'].state, 'success')
752+
t.equal(vm.$asyncComputed['a'].updating, false)
753+
t.equal(vm.$asyncComputed['a'].success, true)
754+
t.equal(vm.$asyncComputed['a'].error, false)
755+
t.equal(vm.$asyncComputed['a'].exception, null)
756+
})
757+
})
758+
759+
test("$asyncComputed[name] handles errors and captures exceptions", t => {
760+
t.plan(7)
761+
const vm = new Vue({
762+
asyncComputed: {
763+
a () {
764+
// eslint-disable-next-line prefer-promise-reject-errors
765+
return Promise.reject('error-message')
766+
}
767+
}
768+
})
769+
t.equal(vm.$asyncComputed['a'].state, 'updating')
770+
pluginOptions.errorHandler = stack => {
771+
t.equal(vm.a, null)
772+
t.equal(vm.$asyncComputed['a'].state, 'error')
773+
t.equal(vm.$asyncComputed['a'].updating, false)
774+
t.equal(vm.$asyncComputed['a'].success, false)
775+
t.equal(vm.$asyncComputed['a'].error, true)
776+
t.equal(vm.$asyncComputed['a'].exception, 'error-message')
777+
pluginOptions.errorHandler = baseErrorCallback
778+
}
779+
})
780+
781+
test("$asyncComputed[name].update triggers re-evaluation", t => {
782+
let valueToReturn = 1
783+
t.plan(5)
784+
const vm = new Vue({
785+
asyncComputed: {
786+
a () {
787+
return new Promise(resolve => {
788+
resolve(valueToReturn)
789+
})
790+
}
791+
}
792+
})
793+
794+
Vue.nextTick(() => {
795+
t.equal(vm.a, 1)
796+
valueToReturn = 2
797+
t.equal(vm.$asyncComputed['a'].state, 'success')
798+
vm.$asyncComputed['a'].update()
799+
t.equal(vm.$asyncComputed['a'].state, 'updating')
800+
801+
Vue.nextTick(() => {
802+
t.equal(vm.a, 2)
803+
valueToReturn = 3
804+
805+
Vue.nextTick(() => {
806+
t.equal(vm.a, 2)
807+
})
808+
})
809+
})
810+
})

0 commit comments

Comments
 (0)