Skip to content

Commit 2aa5288

Browse files
author
Rob McVey
committed
Add promise support to AsyncStorage
Summary: Since `AsyncStorage` is the primary cache, it would be nice to stick with fetch's promise model and make the common use-case of: 1) check cache 2) make request if cache is invalid more straightforward. Currently if I want to check a cache prior to using fetch (or another promise-based XHR lib) I have to provide a callback. I left the callback support and `resolve`/`reject` the promise after the callback has been applied. Closes facebook#593 Github Author: Rob McVey <mcvey@thecollective-la.com> Test Plan: Imported from GitHub, without a `Test Plan:` line.
1 parent dc5be73 commit 2aa5288

File tree

2 files changed

+139
-76
lines changed

2 files changed

+139
-76
lines changed

Examples/UIExplorer/AsyncStorageExample.js

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,17 @@ var COLORS = ['red', 'orange', 'yellow', 'green', 'blue'];
2929

3030
var BasicStorageExample = React.createClass({
3131
componentDidMount() {
32-
AsyncStorage.getItem(STORAGE_KEY, (error, value) => {
33-
if (error) {
34-
this._appendMessage('AsyncStorage error: ' + error.message);
35-
} else if (value !== null) {
36-
this.setState({selectedValue: value});
37-
this._appendMessage('Recovered selection from disk: ' + value);
38-
} else {
39-
this._appendMessage('Initialized with no selection on disk.');
40-
}
41-
});
32+
AsyncStorage.getItem(STORAGE_KEY)
33+
.then((value) => {
34+
if (value !== null){
35+
this.setState({selectedValue: value});
36+
this._appendMessage('Recovered selection from disk: ' + value);
37+
} else {
38+
this._appendMessage('Initialized with no selection on disk.');
39+
}
40+
})
41+
.catch((error) => this._appendMessage('AsyncStorage error: ' + error.message))
42+
.done();
4243
},
4344
getInitialState() {
4445
return {
@@ -81,23 +82,17 @@ var BasicStorageExample = React.createClass({
8182

8283
_onValueChange(selectedValue) {
8384
this.setState({selectedValue});
84-
AsyncStorage.setItem(STORAGE_KEY, selectedValue, (error) => {
85-
if (error) {
86-
this._appendMessage('AsyncStorage error: ' + error.message);
87-
} else {
88-
this._appendMessage('Saved selection to disk: ' + selectedValue);
89-
}
90-
});
85+
AsyncStorage.setItem(STORAGE_KEY, selectedValue)
86+
.then(() => this._appendMessage('Saved selection to disk: ' + selectedValue))
87+
.catch((error) => this._appendMessage('AsyncStorage error: ' + error.message))
88+
.done();
9189
},
9290

9391
_removeStorage() {
94-
AsyncStorage.removeItem(STORAGE_KEY, (error) => {
95-
if (error) {
96-
this._appendMessage('AsyncStorage error: ' + error.message);
97-
} else {
98-
this._appendMessage('Selection removed from disk.');
99-
}
100-
});
92+
AsyncStorage.removeItem(STORAGE_KEY)
93+
.then(() => this._appendMessage('Selection removed from disk.'))
94+
.catch((error) => { this._appendMessage('AsyncStorage error: ' + error.message) })
95+
.done();
10196
},
10297

10398
_appendMessage(message) {

Libraries/Storage/AsyncStorage.ios.js

Lines changed: 120 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -27,79 +27,124 @@ var RCTAsyncStorage = RCTAsyncRocksDBStorage || RCTAsyncLocalStorage;
2727
* operates globally.
2828
*
2929
* This JS code is a simple facad over the native iOS implementation to provide
30-
* a clear JS API, real Error objects, and simple non-multi functions.
30+
* a clear JS API, real Error objects, and simple non-multi functions. Each
31+
* method returns a `Promise` object.
3132
*/
3233
var AsyncStorage = {
3334
/**
3435
* Fetches `key` and passes the result to `callback`, along with an `Error` if
35-
* there is any.
36+
* there is any. Returns a `Promise` object.
3637
*/
3738
getItem: function(
3839
key: string,
3940
callback: (error: ?Error, result: ?string) => void
40-
): void {
41-
RCTAsyncStorage.multiGet([key], function(errors, result) {
42-
// Unpack result to get value from [[key,value]]
43-
var value = (result && result[0] && result[0][1]) ? result[0][1] : null;
44-
callback((errors && convertError(errors[0])) || null, value);
41+
): Promise {
42+
return new Promise((resolve, reject) => {
43+
RCTAsyncStorage.multiGet([key], function(errors, result) {
44+
// Unpack result to get value from [[key,value]]
45+
var value = (result && result[0] && result[0][1]) ? result[0][1] : null;
46+
callback && callback((errors && convertError(errors[0])) || null, value);
47+
if (errors) {
48+
reject(convertError(errors[0]));
49+
} else {
50+
resolve(value);
51+
}
52+
});
4553
});
4654
},
4755

4856
/**
4957
* Sets `value` for `key` and calls `callback` on completion, along with an
50-
* `Error` if there is any.
58+
* `Error` if there is any. Returns a `Promise` object.
5159
*/
5260
setItem: function(
5361
key: string,
5462
value: string,
5563
callback: ?(error: ?Error) => void
56-
): void {
57-
RCTAsyncStorage.multiSet([[key,value]], function(errors) {
58-
callback && callback((errors && convertError(errors[0])) || null);
64+
): Promise {
65+
return new Promise((resolve, reject) => {
66+
RCTAsyncStorage.multiSet([[key,value]], function(errors) {
67+
callback && callback((errors && convertError(errors[0])) || null);
68+
if (errors) {
69+
reject(convertError(errors[0]));
70+
} else {
71+
resolve(null);
72+
}
73+
});
5974
});
6075
},
61-
76+
/**
77+
* Returns a `Promise` object.
78+
*/
6279
removeItem: function(
6380
key: string,
6481
callback: ?(error: ?Error) => void
65-
): void {
66-
RCTAsyncStorage.multiRemove([key], function(errors) {
67-
callback && callback((errors && convertError(errors[0])) || null);
82+
): Promise {
83+
return new Promise((resolve, reject) => {
84+
RCTAsyncStorage.multiRemove([key], function(errors) {
85+
callback && callback((errors && convertError(errors[0])) || null);
86+
if (errors) {
87+
reject(convertError(errors[0]));
88+
} else {
89+
resolve(null);
90+
}
91+
});
6892
});
6993
},
7094

7195
/**
72-
* Merges existing value with input value, assuming they are stringified json.
96+
* Merges existing value with input value, assuming they are stringified json. Returns a `Promise` object.
7397
*
7498
* Not supported by all native implementations.
7599
*/
76100
mergeItem: function(
77101
key: string,
78102
value: string,
79103
callback: ?(error: ?Error) => void
80-
): void {
81-
RCTAsyncStorage.multiMerge([[key,value]], function(errors) {
82-
callback && callback((errors && convertError(errors[0])) || null);
104+
): Promise {
105+
return new Promise((resolve, reject) => {
106+
RCTAsyncStorage.multiMerge([[key,value]], function(errors) {
107+
callback && callback((errors && convertError(errors[0])) || null);
108+
if (errors) {
109+
reject(convertError(errors[0]));
110+
} else {
111+
resolve(null);
112+
}
113+
});
83114
});
84115
},
85116

86117
/**
87118
* Erases *all* AsyncStorage for all clients, libraries, etc. You probably
88119
* don't want to call this - use removeItem or multiRemove to clear only your
89-
* own keys instead.
120+
* own keys instead. Returns a `Promise` object.
90121
*/
91-
clear: function(callback: ?(error: ?Error) => void) {
92-
RCTAsyncStorage.clear(function(error) {
93-
callback && callback(convertError(error));
122+
clear: function(callback: ?(error: ?Error) => void): Promise {
123+
return new Promise((resolve, reject) => {
124+
RCTAsyncStorage.clear(function(error) {
125+
callback && callback(convertError(error));
126+
if (error && convertError(error)){
127+
reject(convertError(error));
128+
} else {
129+
resolve(null);
130+
}
131+
});
94132
});
95133
},
96134

97135
/**
98-
* Gets *all* keys known to the system, for all callers, libraries, etc.
136+
* Gets *all* keys known to the system, for all callers, libraries, etc. Returns a `Promise` object.
99137
*/
100-
getAllKeys: function(callback: (error: ?Error) => void) {
101-
RCTAsyncStorage.getAllKeys(function(error, keys) {
102-
callback(convertError(error), keys);
138+
getAllKeys: function(callback: (error: ?Error) => void): Promise {
139+
return new Promise((resolve, reject) => {
140+
RCTAsyncStorage.getAllKeys(function(error, keys) {
141+
callback && callback(convertError(error), keys);
142+
if (error) {
143+
reject(convertError(error));
144+
} else {
145+
resolve(keys);
146+
}
147+
});
103148
});
104149
},
105150

@@ -115,67 +160,90 @@ var AsyncStorage = {
115160

116161
/**
117162
* multiGet invokes callback with an array of key-value pair arrays that
118-
* matches the input format of multiSet.
163+
* matches the input format of multiSet. Returns a `Promise` object.
119164
*
120165
* multiGet(['k1', 'k2'], cb) -> cb([['k1', 'val1'], ['k2', 'val2']])
121166
*/
122167
multiGet: function(
123168
keys: Array<string>,
124169
callback: (errors: ?Array<Error>, result: ?Array<Array<string>>) => void
125-
): void {
126-
RCTAsyncStorage.multiGet(keys, function(errors, result) {
127-
callback(
128-
(errors && errors.map((error) => convertError(error))) || null,
129-
result
130-
);
170+
): Promise {
171+
return new Promise((resolve, reject) => {
172+
RCTAsyncStorage.multiGet(keys, function(errors, result) {
173+
var error = (errors && errors.map((error) => convertError(error))) || null;
174+
callback && callback(error, result);
175+
if (errors) {
176+
reject(error);
177+
} else {
178+
resolve(result);
179+
}
180+
});
131181
});
132182
},
133183

134184
/**
135185
* multiSet and multiMerge take arrays of key-value array pairs that match
136-
* the output of multiGet, e.g.
186+
* the output of multiGet, e.g. Returns a `Promise` object.
137187
*
138188
* multiSet([['k1', 'val1'], ['k2', 'val2']], cb);
139189
*/
140190
multiSet: function(
141191
keyValuePairs: Array<Array<string>>,
142192
callback: ?(errors: ?Array<Error>) => void
143-
): void {
144-
RCTAsyncStorage.multiSet(keyValuePairs, function(errors) {
145-
callback && callback(
146-
(errors && errors.map((error) => convertError(error))) || null
147-
);
193+
): Promise {
194+
return new Promise((resolve, reject) => {
195+
RCTAsyncStorage.multiSet(keyValuePairs, function(errors) {
196+
var error = (errors && errors.map((error) => convertError(error))) || null;
197+
callback && callback(error);
198+
if (errors) {
199+
reject(error);
200+
} else {
201+
resolve(null);
202+
}
203+
});
148204
});
149205
},
150206

151207
/**
152-
* Delete all the keys in the `keys` array.
208+
* Delete all the keys in the `keys` array. Returns a `Promise` object.
153209
*/
154210
multiRemove: function(
155211
keys: Array<string>,
156212
callback: ?(errors: ?Array<Error>) => void
157-
): void {
158-
RCTAsyncStorage.multiRemove(keys, function(errors) {
159-
callback && callback(
160-
(errors && errors.map((error) => convertError(error))) || null
161-
);
213+
): Promise {
214+
return new Promise((resolve, reject) => {
215+
RCTAsyncStorage.multiRemove(keys, function(errors) {
216+
var error = (errors && errors.map((error) => convertError(error))) || null;
217+
callback && callback(error);
218+
if (errors) {
219+
reject(error);
220+
} else {
221+
resolve(null);
222+
}
223+
});
162224
});
163225
},
164226

165227
/**
166228
* Merges existing values with input values, assuming they are stringified
167-
* json.
229+
* json. Returns a `Promise` object.
168230
*
169231
* Not supported by all native implementations.
170232
*/
171233
multiMerge: function(
172234
keyValuePairs: Array<Array<string>>,
173235
callback: ?(errors: ?Array<Error>) => void
174-
): void {
175-
RCTAsyncStorage.multiMerge(keyValuePairs, function(errors) {
176-
callback && callback(
177-
(errors && errors.map((error) => convertError(error))) || null
178-
);
236+
): Promise {
237+
return new Promise((resolve, reject) => {
238+
RCTAsyncStorage.multiMerge(keyValuePairs, function(errors) {
239+
var error = (errors && errors.map((error) => convertError(error))) || null;
240+
callback && callback(error);
241+
if (errors) {
242+
reject(error);
243+
} else {
244+
resolve(null);
245+
}
246+
});
179247
});
180248
},
181249
};

0 commit comments

Comments
 (0)