diff options
author | Stefan Malzner <stefan@adlk.io> | 2017-10-13 12:29:40 +0200 |
---|---|---|
committer | Stefan Malzner <stefan@adlk.io> | 2017-10-13 12:29:40 +0200 |
commit | 58cda9cc7fb79ca9df6746de7f9662bc08dc156a (patch) | |
tree | 1211600c2a5d3b5f81c435c6896618111a611720 /src/stores/lib/CachedRequest.js | |
download | ferdium-app-58cda9cc7fb79ca9df6746de7f9662bc08dc156a.tar.gz ferdium-app-58cda9cc7fb79ca9df6746de7f9662bc08dc156a.tar.zst ferdium-app-58cda9cc7fb79ca9df6746de7f9662bc08dc156a.zip |
initial commit
Diffstat (limited to 'src/stores/lib/CachedRequest.js')
-rw-r--r-- | src/stores/lib/CachedRequest.js | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/src/stores/lib/CachedRequest.js b/src/stores/lib/CachedRequest.js new file mode 100644 index 000000000..c0c3d40a1 --- /dev/null +++ b/src/stores/lib/CachedRequest.js | |||
@@ -0,0 +1,106 @@ | |||
1 | // @flow | ||
2 | import { action } from 'mobx'; | ||
3 | import { isEqual, remove } from 'lodash'; | ||
4 | import Request from './Request'; | ||
5 | |||
6 | export default class CachedRequest extends Request { | ||
7 | _apiCalls = []; | ||
8 | _isInvalidated = true; | ||
9 | |||
10 | execute(...callArgs) { | ||
11 | // Do not continue if this request is already loading | ||
12 | if (this._isWaitingForResponse) return this; | ||
13 | |||
14 | // Very simple caching strategy -> only continue if the call / args changed | ||
15 | // or the request was invalidated manually from outside | ||
16 | const existingApiCall = this._findApiCall(callArgs); | ||
17 | |||
18 | // Invalidate if new or different api call will be done | ||
19 | if (existingApiCall && existingApiCall !== this._currentApiCall) { | ||
20 | this._isInvalidated = true; | ||
21 | this._currentApiCall = existingApiCall; | ||
22 | } else if (!existingApiCall) { | ||
23 | this._isInvalidated = true; | ||
24 | this._currentApiCall = this._addApiCall(callArgs); | ||
25 | } | ||
26 | |||
27 | // Do not continue if this request is not invalidated (see above) | ||
28 | if (!this._isInvalidated) return this; | ||
29 | |||
30 | // This timeout is necessary to avoid warnings from mobx | ||
31 | // regarding triggering actions as side-effect of getters | ||
32 | setTimeout(action(() => { | ||
33 | this.isExecuting = true; | ||
34 | // Apply the previous result from this call immediately (cached) | ||
35 | if (existingApiCall) { | ||
36 | this.result = existingApiCall.result; | ||
37 | } | ||
38 | }), 0); | ||
39 | |||
40 | // Issue api call & save it as promise that is handled to update the results of the operation | ||
41 | this._promise = new Promise((resolve, reject) => { | ||
42 | this._api[this._method](...callArgs) | ||
43 | .then((result) => { | ||
44 | setTimeout(action(() => { | ||
45 | this.result = result; | ||
46 | if (this._currentApiCall) this._currentApiCall.result = result; | ||
47 | this.isExecuting = false; | ||
48 | this.isError = false; | ||
49 | this.wasExecuted = true; | ||
50 | this._isInvalidated = false; | ||
51 | this._isWaitingForResponse = false; | ||
52 | this._triggerHooks(); | ||
53 | resolve(result); | ||
54 | }), 1); | ||
55 | return result; | ||
56 | }) | ||
57 | .catch(action((error) => { | ||
58 | setTimeout(action(() => { | ||
59 | this.error = error; | ||
60 | this.isExecuting = false; | ||
61 | this.isError = true; | ||
62 | this.wasExecuted = true; | ||
63 | this._isWaitingForResponse = false; | ||
64 | this._triggerHooks(); | ||
65 | reject(error); | ||
66 | }), 1); | ||
67 | })); | ||
68 | }); | ||
69 | |||
70 | this._isWaitingForResponse = true; | ||
71 | return this; | ||
72 | } | ||
73 | |||
74 | invalidate(options = { immediately: false }) { | ||
75 | this._isInvalidated = true; | ||
76 | if (options.immediately && this._currentApiCall) { | ||
77 | return this.execute(...this._currentApiCall.args); | ||
78 | } | ||
79 | return this; | ||
80 | } | ||
81 | |||
82 | patch(modify) { | ||
83 | return new Promise((resolve) => { | ||
84 | setTimeout(action(() => { | ||
85 | const override = modify(this.result); | ||
86 | if (override !== undefined) this.result = override; | ||
87 | if (this._currentApiCall) this._currentApiCall.result = this.result; | ||
88 | resolve(this); | ||
89 | }), 0); | ||
90 | }); | ||
91 | } | ||
92 | |||
93 | removeCacheForCallWith(...args) { | ||
94 | remove(this._apiCalls, c => isEqual(c.args, args)); | ||
95 | } | ||
96 | |||
97 | _addApiCall(args) { | ||
98 | const newCall = { args, result: null }; | ||
99 | this._apiCalls.push(newCall); | ||
100 | return newCall; | ||
101 | } | ||
102 | |||
103 | _findApiCall(args) { | ||
104 | return this._apiCalls.find(c => isEqual(c.args, args)); | ||
105 | } | ||
106 | } | ||