Skip to content

Commit fbba1d8

Browse files
committed
Distributing my async-computed changes
see foxbenjaminfox#51
1 parent 0a92b1c commit fbba1d8

File tree

2 files changed

+456
-0
lines changed

2 files changed

+456
-0
lines changed

Diff for: dist/vue-async-computed.esnext.js

+229
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
(function (global, factory) {
2+
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3+
typeof define === 'function' && define.amd ? define(factory) :
4+
(global.AsyncComputed = factory());
5+
}(this, (function () { 'use strict';
6+
7+
function isComputedLazy (item) {
8+
return item.hasOwnProperty('lazy') && item.lazy
9+
}
10+
11+
function isLazyActive (vm, key) {
12+
return vm[lazyActivePrefix + key]
13+
}
14+
15+
const lazyActivePrefix = 'async_computed$lazy_active$',
16+
lazyDataPrefix = 'async_computed$lazy_data$';
17+
18+
function initLazy (data, key) {
19+
data[lazyActivePrefix + key] = false;
20+
data[lazyDataPrefix + key] = null;
21+
}
22+
23+
function makeLazyComputed (key) {
24+
return {
25+
get () {
26+
this[lazyActivePrefix + key] = true;
27+
return this[lazyDataPrefix + key]
28+
},
29+
set (value) {
30+
this[lazyDataPrefix + key] = value;
31+
}
32+
}
33+
}
34+
35+
function silentSetLazy (vm, key, value) {
36+
vm[lazyDataPrefix + key] = value;
37+
}
38+
function silentGetLazy (vm, key) {
39+
return vm[lazyDataPrefix + key]
40+
}
41+
42+
const prefix = '_async_computed$';
43+
const DidNotUpdate = typeof Symbol === 'function' ? Symbol('did-not-update') : {};
44+
45+
const AsyncComputed = {
46+
install (Vue, pluginOptions) {
47+
pluginOptions = pluginOptions || {};
48+
49+
Vue.config
50+
.optionMergeStrategies
51+
.asyncComputed = Vue.config.optionMergeStrategies.computed;
52+
53+
Vue.mixin({
54+
beforeCreate () {
55+
const optionData = this.$options.data;
56+
const asyncComputed = this.$options.asyncComputed || {};
57+
this.$asyncComputed = {};
58+
59+
for (const key in this.$options.computed) {
60+
if (this.$options.computed[key].asynchronous) {
61+
asyncComputed[key] = this.$options.computed[key];
62+
delete this.$options.computed[key];
63+
}
64+
}
65+
66+
if (!Object.keys(asyncComputed).length) return
67+
68+
this.$options.asyncComputed = asyncComputed;
69+
70+
if (!this.$options.computed) this.$options.computed = {};
71+
72+
for (const key in asyncComputed) {
73+
const getter = getterFn(key, this.$options.asyncComputed[key]);
74+
this.$options.computed[prefix + key] = getter;
75+
}
76+
77+
this.$options.data = function vueAsyncComputedInjectedDataFn () {
78+
const data = (
79+
(typeof optionData === 'function')
80+
? optionData.call(this)
81+
: optionData
82+
) || {};
83+
for (const key in asyncComputed) {
84+
const item = this.$options.asyncComputed[key];
85+
if (isComputedLazy(item)) {
86+
initLazy(data, key);
87+
this.$options.computed[key] = makeLazyComputed(key);
88+
} else {
89+
data[key] = null;
90+
}
91+
}
92+
return data
93+
};
94+
},
95+
created () {
96+
for (const key in this.$options.asyncComputed || {}) {
97+
const item = this.$options.asyncComputed[key],
98+
value = generateDefault.call(this, item, pluginOptions);
99+
if (isComputedLazy(item)) {
100+
silentSetLazy(this, key, value);
101+
} else {
102+
this[key] = value;
103+
}
104+
}
105+
106+
for (const key in this.$options.asyncComputed || {}) {
107+
let promiseId = 0;
108+
const watcher = newPromise => {
109+
const thisPromise = ++promiseId;
110+
111+
if (newPromise === DidNotUpdate) {
112+
return
113+
}
114+
115+
if (!newPromise || !newPromise.then) {
116+
newPromise = Promise.resolve(newPromise);
117+
}
118+
setAsyncState(this.$asyncComputed[key], 'updating');
119+
120+
newPromise.then(value => {
121+
if (thisPromise !== promiseId) return
122+
setAsyncState(this.$asyncComputed[key], 'success');
123+
this[key] = value;
124+
}).catch(err => {
125+
if (thisPromise !== promiseId) return
126+
127+
setAsyncState(this.$asyncComputed[key], 'error');
128+
this.$asyncComputed[key].exception = err;
129+
if (pluginOptions.errorHandler === false) return
130+
131+
const handler = (pluginOptions.errorHandler === undefined)
132+
? console.error.bind(console, 'Error evaluating async computed property:')
133+
: pluginOptions.errorHandler;
134+
135+
if (pluginOptions.useRawError) {
136+
handler(err);
137+
} else {
138+
handler(err.stack);
139+
}
140+
});
141+
};
142+
this.$asyncComputed[key] = {
143+
exception: null,
144+
update: () => {
145+
watcher(getterOnly(this.$options.asyncComputed[key])());
146+
}
147+
};
148+
setAsyncState(this.$asyncComputed[key], 'updating');
149+
this.$watch(prefix + key, watcher, { immediate: true });
150+
}
151+
}
152+
});
153+
}
154+
};
155+
156+
function setAsyncState (stateObject, state) {
157+
stateObject.state = state;
158+
stateObject.updating = state === 'updating';
159+
stateObject.error = state === 'error';
160+
stateObject.success = state === 'success';
161+
}
162+
163+
function getterOnly (fn) {
164+
if (typeof fn === 'function') return fn
165+
166+
return fn.get
167+
}
168+
169+
function getterFn (key, fn) {
170+
if (typeof fn === 'function') return fn
171+
172+
let getter = fn.get;
173+
174+
if (fn.hasOwnProperty('watch')) {
175+
const previousGetter = getter;
176+
getter = function getter () {
177+
fn.watch.call(this);
178+
return previousGetter.call(this)
179+
};
180+
}
181+
182+
if (fn.hasOwnProperty('shouldUpdate')) {
183+
const previousGetter = getter;
184+
getter = function getter () {
185+
if (fn.shouldUpdate.call(this)) {
186+
return previousGetter.call(this)
187+
}
188+
return DidNotUpdate
189+
};
190+
}
191+
192+
if (isComputedLazy(fn)) {
193+
const nonLazy = getter;
194+
getter = function lazyGetter () {
195+
if (isLazyActive(this, key)) {
196+
return nonLazy.call(this)
197+
} else {
198+
return silentGetLazy(this, key)
199+
}
200+
};
201+
}
202+
return getter
203+
}
204+
205+
function generateDefault (fn, pluginOptions) {
206+
let defaultValue = null;
207+
208+
if ('default' in fn) {
209+
defaultValue = fn.default;
210+
} else if ('default' in pluginOptions) {
211+
defaultValue = pluginOptions.default;
212+
}
213+
214+
if (typeof defaultValue === 'function') {
215+
return defaultValue.call(this)
216+
} else {
217+
return defaultValue
218+
}
219+
}
220+
221+
/* istanbul ignore if */
222+
if (typeof window !== 'undefined' && window.Vue) {
223+
// Auto install in dist mode
224+
window.Vue.use(AsyncComputed);
225+
}
226+
227+
return AsyncComputed;
228+
229+
})));

0 commit comments

Comments
 (0)