瀏覽代碼

[RN] Protect AbstractApp and localStorage initialization

master
Lyubo Marinov 7 年之前
父節點
當前提交
62c9762793
共有 2 個文件被更改,包括 94 次插入61 次删除
  1. 27
    19
      react/features/app/components/AbstractApp.js
  2. 67
    42
      react/features/base/storage/native/Storage.js

+ 27
- 19
react/features/app/components/AbstractApp.js 查看文件

97
         };
97
         };
98
 
98
 
99
         /**
99
         /**
100
-         * This way we make the mobile version wait until the
101
-         * {@code AsyncStorage} implementation of {@code Storage}
102
-         * properly initializes. On web it does actually nothing, see
103
-         * {@link #_initStorage}.
100
+         * Make the mobile {@code AbstractApp} wait until the
101
+         * {@code AsyncStorage} implementation of {@code Storage} initializes
102
+         * fully.
103
+         *
104
+         * @private
105
+         * @see {@link #_initStorage}
106
+         * @type {Promise}
104
          */
107
          */
105
-        this.init = this._initStorage().then(() => {
106
-            this.setState({
107
-                route: undefined,
108
-                store: this._maybeCreateStore(props)
109
-            });
110
-        });
108
+        this._init
109
+            = this._initStorage()
110
+                .catch(() => { /* AbstractApp should always initialize! */ })
111
+                .then(() =>
112
+                    this.setState({
113
+                        route: undefined,
114
+                        store: this._maybeCreateStore(props)
115
+                    }));
111
     }
116
     }
112
 
117
 
113
     /**
118
     /**
117
      * @inheritdoc
122
      * @inheritdoc
118
      */
123
      */
119
     componentWillMount() {
124
     componentWillMount() {
120
-        this.init.then(() => {
125
+        this._init.then(() => {
121
             const { dispatch } = this._getStore();
126
             const { dispatch } = this._getStore();
122
 
127
 
123
             dispatch(appWillMount(this));
128
             dispatch(appWillMount(this));
175
     componentWillReceiveProps(nextProps) {
180
     componentWillReceiveProps(nextProps) {
176
         const { props } = this;
181
         const { props } = this;
177
 
182
 
178
-        this.init.then(() => {
183
+        this._init.then(() => {
179
             // The consumer of this AbstractApp did not provide a redux store.
184
             // The consumer of this AbstractApp did not provide a redux store.
180
             if (typeof nextProps.store === 'undefined'
185
             if (typeof nextProps.store === 'undefined'
181
 
186
 
236
     }
241
     }
237
 
242
 
238
     /**
243
     /**
239
-     * Delays app start until the {@code Storage} implementation initialises.
240
-     * This is instantaneous on web, but is async on mobile.
244
+     * Delays this {@code AbstractApp}'s startup until the {@code Storage}
245
+     * implementation of {@code localStorage} initializes. While the
246
+     * initialization is instantaneous on Web (with Web Storage API), it is
247
+     * asynchronous on mobile/react-native.
241
      *
248
      *
242
      * @private
249
      * @private
243
-     * @returns {ReactElement}
250
+     * @returns {Promise}
244
      */
251
      */
245
     _initStorage() {
252
     _initStorage() {
246
-        if (typeof window.localStorage._initialized !== 'undefined') {
247
-            return window.localStorage._initialized;
248
-        }
253
+        const localStorageInitializing = window.localStorage._initializing;
249
 
254
 
250
-        return Promise.resolve();
255
+        return (
256
+            typeof localStorageInitializing === 'undefined'
257
+                ? Promise.resolve()
258
+                : localStorageInitializing);
251
     }
259
     }
252
 
260
 
253
     /**
261
     /**

+ 67
- 42
react/features/base/storage/native/Storage.js 查看文件

30
          */
30
          */
31
         this._keyPrefix = keyPrefix;
31
         this._keyPrefix = keyPrefix;
32
 
32
 
33
+        // Perform optional asynchronous initialization.
34
+        const initializing = this._initializeAsync();
35
+
36
+        if (initializing) {
37
+            // Indicate that asynchronous initialization is under way.
38
+            this._initializing = initializing;
39
+
40
+            // When the asynchronous initialization completes, indicate its
41
+            // completion.
42
+            initializing.finally(() => {
43
+                if (this._initializing === initializing) {
44
+                    this._initializing = undefined;
45
+                }
46
+            });
47
+        }
48
+    }
49
+
50
+    /**
51
+     * Removes all keys from this storage.
52
+     *
53
+     * @returns {void}
54
+     */
55
+    clear() {
56
+        for (const key of Object.keys(this)) {
57
+            this.removeItem(key);
58
+        }
59
+    }
60
+
61
+    /**
62
+     * Returns the value associated with a specific key in this storage.
63
+     *
64
+     * @param {string} key - The name of the key to retrieve the value of.
65
+     * @returns {string|null} The value associated with {@code key} or
66
+     * {@code null}.
67
+     */
68
+    getItem(key) {
69
+        return this.hasOwnProperty(key) ? this[key] : null;
70
+    }
71
+
72
+    /**
73
+     * Returns the value associated with a specific key in this {@code Storage}
74
+     * in an async manner. The method is required for the cases where we need
75
+     * the stored data but we're not sure yet whether this {@code Storage} is
76
+     * already initialized (e.g. on app start).
77
+     *
78
+     * @param {string} key - The name of the key to retrieve the value of.
79
+     * @returns {Promise}
80
+     */
81
+    _getItemAsync(key) {
82
+        return (
83
+            (this._initializing || Promise.resolve())
84
+                .catch(() => { /* _getItemAsync should always resolve! */ })
85
+                .then(() => this.getItem(key)));
86
+    }
87
+
88
+    /**
89
+     * Performs asynchronous initialization of this {@code Storage} instance
90
+     * such as loading all keys from {@link AsyncStorage}.
91
+     *
92
+     * @private
93
+     * @returns {Promise}
94
+     */
95
+    _initializeAsync() {
33
         if (typeof this._keyPrefix !== 'undefined') {
96
         if (typeof this._keyPrefix !== 'undefined') {
34
             // Load all previously persisted data items from React Native's
97
             // Load all previously persisted data items from React Native's
35
             // AsyncStorage.
98
             // AsyncStorage.
36
 
99
 
37
-            this._initialized = new Promise(resolve => {
100
+            return new Promise(resolve => {
38
                 AsyncStorage.getAllKeys().then((...getAllKeysCallbackArgs) => {
101
                 AsyncStorage.getAllKeys().then((...getAllKeysCallbackArgs) => {
39
-                    // XXX The keys argument of getAllKeys' callback may
40
-                    // or may not be preceded by an error argument.
102
+                    // XXX The keys argument of getAllKeys' callback may or may
103
+                    // not be preceded by an error argument.
41
                     const keys
104
                     const keys
42
                         = getAllKeysCallbackArgs[
105
                         = getAllKeysCallbackArgs[
43
                             getAllKeysCallbackArgs.length - 1
106
                             getAllKeysCallbackArgs.length - 1
73
                 });
136
                 });
74
             });
137
             });
75
         }
138
         }
76
-    }
77
-
78
-    /**
79
-     * Removes all keys from this storage.
80
-     *
81
-     * @returns {void}
82
-     */
83
-    clear() {
84
-        for (const key of Object.keys(this)) {
85
-            this.removeItem(key);
86
-        }
87
-    }
88
 
139
 
89
-    /**
90
-     * Returns the value associated with a specific key in this storage.
91
-     *
92
-     * @param {string} key - The name of the key to retrieve the value of.
93
-     * @returns {string|null} The value associated with {@code key} or
94
-     * {@code null}.
95
-     */
96
-    getItem(key) {
97
-        return this.hasOwnProperty(key) ? this[key] : null;
98
-    }
99
-
100
-    /**
101
-     * Returns the value associated with a specific key in this storage in an
102
-     * async manner. This method is required for those cases where we need the
103
-     * stored data but we're not sure yet whether the {@code Storage} is already
104
-     * initialised or not - e.g. on app start.
105
-     *
106
-     * @param {string} key - The name of the key to retrieve the value of.
107
-     * @private
108
-     * @returns {Promise}
109
-     */
110
-    _getItemAsync(key) {
111
-        return new Promise(
112
-            resolve =>
113
-                AsyncStorage.getItem(
114
-                    `${String(this._keyPrefix)}${key}`,
115
-                    (error, result) => resolve(result ? result : null)));
140
+        return undefined;
116
     }
141
     }
117
 
142
 
118
     /**
143
     /**

Loading…
取消
儲存