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 https://github.com/facebook/react-native/pull/593 Github Author: Rob McVey <mcvey@thecollective-la.com> Test Plan: Imported from GitHub, without a `Test Plan:` line.
This commit is contained in:
parent
dc5be73a94
commit
2aa52880b7
|
@ -29,16 +29,17 @@ var COLORS = ['red', 'orange', 'yellow', 'green', 'blue'];
|
|||
|
||||
var BasicStorageExample = React.createClass({
|
||||
componentDidMount() {
|
||||
AsyncStorage.getItem(STORAGE_KEY, (error, value) => {
|
||||
if (error) {
|
||||
this._appendMessage('AsyncStorage error: ' + error.message);
|
||||
} else if (value !== null) {
|
||||
this.setState({selectedValue: value});
|
||||
this._appendMessage('Recovered selection from disk: ' + value);
|
||||
} else {
|
||||
this._appendMessage('Initialized with no selection on disk.');
|
||||
}
|
||||
});
|
||||
AsyncStorage.getItem(STORAGE_KEY)
|
||||
.then((value) => {
|
||||
if (value !== null){
|
||||
this.setState({selectedValue: value});
|
||||
this._appendMessage('Recovered selection from disk: ' + value);
|
||||
} else {
|
||||
this._appendMessage('Initialized with no selection on disk.');
|
||||
}
|
||||
})
|
||||
.catch((error) => this._appendMessage('AsyncStorage error: ' + error.message))
|
||||
.done();
|
||||
},
|
||||
getInitialState() {
|
||||
return {
|
||||
|
@ -81,23 +82,17 @@ var BasicStorageExample = React.createClass({
|
|||
|
||||
_onValueChange(selectedValue) {
|
||||
this.setState({selectedValue});
|
||||
AsyncStorage.setItem(STORAGE_KEY, selectedValue, (error) => {
|
||||
if (error) {
|
||||
this._appendMessage('AsyncStorage error: ' + error.message);
|
||||
} else {
|
||||
this._appendMessage('Saved selection to disk: ' + selectedValue);
|
||||
}
|
||||
});
|
||||
AsyncStorage.setItem(STORAGE_KEY, selectedValue)
|
||||
.then(() => this._appendMessage('Saved selection to disk: ' + selectedValue))
|
||||
.catch((error) => this._appendMessage('AsyncStorage error: ' + error.message))
|
||||
.done();
|
||||
},
|
||||
|
||||
_removeStorage() {
|
||||
AsyncStorage.removeItem(STORAGE_KEY, (error) => {
|
||||
if (error) {
|
||||
this._appendMessage('AsyncStorage error: ' + error.message);
|
||||
} else {
|
||||
this._appendMessage('Selection removed from disk.');
|
||||
}
|
||||
});
|
||||
AsyncStorage.removeItem(STORAGE_KEY)
|
||||
.then(() => this._appendMessage('Selection removed from disk.'))
|
||||
.catch((error) => { this._appendMessage('AsyncStorage error: ' + error.message) })
|
||||
.done();
|
||||
},
|
||||
|
||||
_appendMessage(message) {
|
||||
|
|
|
@ -27,49 +27,73 @@ var RCTAsyncStorage = RCTAsyncRocksDBStorage || RCTAsyncLocalStorage;
|
|||
* operates globally.
|
||||
*
|
||||
* This JS code is a simple facad over the native iOS implementation to provide
|
||||
* a clear JS API, real Error objects, and simple non-multi functions.
|
||||
* a clear JS API, real Error objects, and simple non-multi functions. Each
|
||||
* method returns a `Promise` object.
|
||||
*/
|
||||
var AsyncStorage = {
|
||||
/**
|
||||
* Fetches `key` and passes the result to `callback`, along with an `Error` if
|
||||
* there is any.
|
||||
* there is any. Returns a `Promise` object.
|
||||
*/
|
||||
getItem: function(
|
||||
key: string,
|
||||
callback: (error: ?Error, result: ?string) => void
|
||||
): void {
|
||||
RCTAsyncStorage.multiGet([key], function(errors, result) {
|
||||
// Unpack result to get value from [[key,value]]
|
||||
var value = (result && result[0] && result[0][1]) ? result[0][1] : null;
|
||||
callback((errors && convertError(errors[0])) || null, value);
|
||||
): Promise {
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTAsyncStorage.multiGet([key], function(errors, result) {
|
||||
// Unpack result to get value from [[key,value]]
|
||||
var value = (result && result[0] && result[0][1]) ? result[0][1] : null;
|
||||
callback && callback((errors && convertError(errors[0])) || null, value);
|
||||
if (errors) {
|
||||
reject(convertError(errors[0]));
|
||||
} else {
|
||||
resolve(value);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets `value` for `key` and calls `callback` on completion, along with an
|
||||
* `Error` if there is any.
|
||||
* `Error` if there is any. Returns a `Promise` object.
|
||||
*/
|
||||
setItem: function(
|
||||
key: string,
|
||||
value: string,
|
||||
callback: ?(error: ?Error) => void
|
||||
): void {
|
||||
RCTAsyncStorage.multiSet([[key,value]], function(errors) {
|
||||
callback && callback((errors && convertError(errors[0])) || null);
|
||||
): Promise {
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTAsyncStorage.multiSet([[key,value]], function(errors) {
|
||||
callback && callback((errors && convertError(errors[0])) || null);
|
||||
if (errors) {
|
||||
reject(convertError(errors[0]));
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a `Promise` object.
|
||||
*/
|
||||
removeItem: function(
|
||||
key: string,
|
||||
callback: ?(error: ?Error) => void
|
||||
): void {
|
||||
RCTAsyncStorage.multiRemove([key], function(errors) {
|
||||
callback && callback((errors && convertError(errors[0])) || null);
|
||||
): Promise {
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTAsyncStorage.multiRemove([key], function(errors) {
|
||||
callback && callback((errors && convertError(errors[0])) || null);
|
||||
if (errors) {
|
||||
reject(convertError(errors[0]));
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Merges existing value with input value, assuming they are stringified json.
|
||||
* Merges existing value with input value, assuming they are stringified json. Returns a `Promise` object.
|
||||
*
|
||||
* Not supported by all native implementations.
|
||||
*/
|
||||
|
@ -77,29 +101,50 @@ var AsyncStorage = {
|
|||
key: string,
|
||||
value: string,
|
||||
callback: ?(error: ?Error) => void
|
||||
): void {
|
||||
RCTAsyncStorage.multiMerge([[key,value]], function(errors) {
|
||||
callback && callback((errors && convertError(errors[0])) || null);
|
||||
): Promise {
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTAsyncStorage.multiMerge([[key,value]], function(errors) {
|
||||
callback && callback((errors && convertError(errors[0])) || null);
|
||||
if (errors) {
|
||||
reject(convertError(errors[0]));
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Erases *all* AsyncStorage for all clients, libraries, etc. You probably
|
||||
* don't want to call this - use removeItem or multiRemove to clear only your
|
||||
* own keys instead.
|
||||
* own keys instead. Returns a `Promise` object.
|
||||
*/
|
||||
clear: function(callback: ?(error: ?Error) => void) {
|
||||
RCTAsyncStorage.clear(function(error) {
|
||||
callback && callback(convertError(error));
|
||||
clear: function(callback: ?(error: ?Error) => void): Promise {
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTAsyncStorage.clear(function(error) {
|
||||
callback && callback(convertError(error));
|
||||
if (error && convertError(error)){
|
||||
reject(convertError(error));
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets *all* keys known to the system, for all callers, libraries, etc.
|
||||
* Gets *all* keys known to the system, for all callers, libraries, etc. Returns a `Promise` object.
|
||||
*/
|
||||
getAllKeys: function(callback: (error: ?Error) => void) {
|
||||
RCTAsyncStorage.getAllKeys(function(error, keys) {
|
||||
callback(convertError(error), keys);
|
||||
getAllKeys: function(callback: (error: ?Error) => void): Promise {
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTAsyncStorage.getAllKeys(function(error, keys) {
|
||||
callback && callback(convertError(error), keys);
|
||||
if (error) {
|
||||
reject(convertError(error));
|
||||
} else {
|
||||
resolve(keys);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -115,67 +160,90 @@ var AsyncStorage = {
|
|||
|
||||
/**
|
||||
* multiGet invokes callback with an array of key-value pair arrays that
|
||||
* matches the input format of multiSet.
|
||||
* matches the input format of multiSet. Returns a `Promise` object.
|
||||
*
|
||||
* multiGet(['k1', 'k2'], cb) -> cb([['k1', 'val1'], ['k2', 'val2']])
|
||||
*/
|
||||
multiGet: function(
|
||||
keys: Array<string>,
|
||||
callback: (errors: ?Array<Error>, result: ?Array<Array<string>>) => void
|
||||
): void {
|
||||
RCTAsyncStorage.multiGet(keys, function(errors, result) {
|
||||
callback(
|
||||
(errors && errors.map((error) => convertError(error))) || null,
|
||||
result
|
||||
);
|
||||
): Promise {
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTAsyncStorage.multiGet(keys, function(errors, result) {
|
||||
var error = (errors && errors.map((error) => convertError(error))) || null;
|
||||
callback && callback(error, result);
|
||||
if (errors) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* multiSet and multiMerge take arrays of key-value array pairs that match
|
||||
* the output of multiGet, e.g.
|
||||
* the output of multiGet, e.g. Returns a `Promise` object.
|
||||
*
|
||||
* multiSet([['k1', 'val1'], ['k2', 'val2']], cb);
|
||||
*/
|
||||
multiSet: function(
|
||||
keyValuePairs: Array<Array<string>>,
|
||||
callback: ?(errors: ?Array<Error>) => void
|
||||
): void {
|
||||
RCTAsyncStorage.multiSet(keyValuePairs, function(errors) {
|
||||
callback && callback(
|
||||
(errors && errors.map((error) => convertError(error))) || null
|
||||
);
|
||||
): Promise {
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTAsyncStorage.multiSet(keyValuePairs, function(errors) {
|
||||
var error = (errors && errors.map((error) => convertError(error))) || null;
|
||||
callback && callback(error);
|
||||
if (errors) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Delete all the keys in the `keys` array.
|
||||
* Delete all the keys in the `keys` array. Returns a `Promise` object.
|
||||
*/
|
||||
multiRemove: function(
|
||||
keys: Array<string>,
|
||||
callback: ?(errors: ?Array<Error>) => void
|
||||
): void {
|
||||
RCTAsyncStorage.multiRemove(keys, function(errors) {
|
||||
callback && callback(
|
||||
(errors && errors.map((error) => convertError(error))) || null
|
||||
);
|
||||
): Promise {
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTAsyncStorage.multiRemove(keys, function(errors) {
|
||||
var error = (errors && errors.map((error) => convertError(error))) || null;
|
||||
callback && callback(error);
|
||||
if (errors) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Merges existing values with input values, assuming they are stringified
|
||||
* json.
|
||||
* json. Returns a `Promise` object.
|
||||
*
|
||||
* Not supported by all native implementations.
|
||||
*/
|
||||
multiMerge: function(
|
||||
keyValuePairs: Array<Array<string>>,
|
||||
callback: ?(errors: ?Array<Error>) => void
|
||||
): void {
|
||||
RCTAsyncStorage.multiMerge(keyValuePairs, function(errors) {
|
||||
callback && callback(
|
||||
(errors && errors.map((error) => convertError(error))) || null
|
||||
);
|
||||
): Promise {
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTAsyncStorage.multiMerge(keyValuePairs, function(errors) {
|
||||
var error = (errors && errors.map((error) => convertError(error))) || null;
|
||||
callback && callback(error);
|
||||
if (errors) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue