当我在网站上运行时,我如何构建我的应用程序以使用localStorage,当我作为chrome应用程序运行时,如何构建c
How can I structure my app to use localStorage when running on a website, and chrome.storage when running as a Chrome App?
我构建了一个简单的web应用程序,它使用localStorage
将一组任务保存为字符串JSON。它也是Chrome Web Store上的Chrome扩展,该扩展和在VPS上运行的网站的代码库完全相同http://supersimpletasks.com.
我想将我的扩展迁移到Chrome应用程序,这样我就可以访问chrome.storage.sync
API,这将允许我的用户跨设备同步任务。如果我想存储超过5mb的数据,那么使用chrome.storage也会给我更多的灵活性。
然而,当我的应用程序从superimpletesks.com提供服务时,chrome.storage
将不起作用——我需要使用localStorage。
据我所知,localStorage
是同步的,chrome.storage
是异步的,这意味着要重写很多方法,比如下面的方法。这两种方法负责从localStorage检索任务和保存任务。
@getAllTasks: ->
allTasks = localStorage.getItem(DB.db_key)
allTasks = JSON.parse(allTasks) || Arrays.default_data
allTasks
@setAllTasks: (allTasks) ->
localStorage.setItem(DB.db_key, JSON.stringify(allTasks))
Views.showTasks(allTasks)
如何根据环境构建应用程序以使用localStorage或chrome.storage?我预计会遇到什么问题?
解决此问题的方法是创建您自己的存储API。您已经发现localStorage是同步的,而Chrome存储是异步的,但这是一个很容易解决的问题,只需将所有内容视为异步即可。
创建您自己的API,然后使用它来代替所有其他调用。代码中的快速查找/替换可以用新的API替换localStorage调用。
function LocalStorageAsync() {
/**
* Parses a boolean from a string, or the boolean if an actual boolean argument is passed in.
*
* @param {String|Boolean} bool A string representation of a boolean value
* @return {Boolean} Returns a boolean value, if the string can be parsed as a bool.
*/
function parseBool(bool) {
if (typeof bool !== 'string' && typeof bool !== 'boolean')
throw new Error('bool is not of type boolean or string');
if (typeof bool == 'boolean') return bool;
return bool === 'true' ? true : false;
}
/**
* store the key value pair and fire the callback function.
*/
this.setItem = function(key, value, callback) {
if(chrome && chrome.storage) {
chrome.storage.local.set({key: key, value: value}, callback);
} else {
var type = typeof value;
var serializedValue = value;
if(type === 'object') {
serializedValue = JSON.stringify(value);
}
value = type + '::typeOf::' + serializedValue;
window.localStorage.setItem(key, value);
callback();
}
}
/**
* Get the item from storage and fire the callback.
*/
this.getItem = function(key, callback) {
if(chrome && chrome.storage) {
chrome.storage.local.get(key, callback);
} else {
var stronglyTypedValue = window.localStorage.getItem(key);
var type = stronglyTypedValue.split('::typeOf::')[0];
var valueAsString = stronglyTypedValue.split('::typeOf::')[1];
var value;
if(type === 'object') {
value = JSON.parse(valueAsString);
} else if(type === 'boolean') {
value = parseBool(valueAsString);
} else if(type === 'number') {
value = parseFloat(valueAsString);
} else if(type === 'string') {
value = valueAsString;
}
callback(value);
}
}
}
// usage example
l = new LocalStorageAsync();
l.setItem('test',[1,2,3], function() {console.log('test');});
l.getItem('test', function(e) { console.log(e);});
下面的解决方案除了将所有内容都视为异步之外,还克服了一个问题,即localStorage将所有内容转换为字符串。通过将类型信息保留为元数据,我们可以确保getItem操作产生的数据类型与进入的数据类型相同
更重要的是,使用工厂模式的变体,您可以创建两个具体的内部子类,并根据环境返回适当的子类:
function LocalStorageAsync() {
var private = {};
private.LocalStorage = function() {
function parseBool(bool) {
if (typeof bool !== 'string' && typeof bool !== 'boolean')
throw new Error('bool is not of type boolean or string');
if (typeof bool == 'boolean') return bool;
return bool === 'true' ? true : false;
}
this.setItem = function(key, value, callback) { /* localStorage impl... */ };
this.getItem = function(key, callback) { /* ... */ };
};
private.ChromeStorage = function() {
this.setItem = function(key, value, callback) { /* chrome.storage impl... */ };
this.getItem = function(key, callback) { /* ... */ };
}
if(chrome && chrome.storage)
return new private.ChromeStorage();
else
return new private.LocalStorage();
};
这是我最终得到的代码,它对我想做的事情很有效。
这不是真正的异步代码,尤其是在Storage API中的ChromeStorage.set()方法中,我没有使用回调。理想情况下,您希望使用回调来进行一些错误处理。
localStorage或chrome.storage
首先,决定是使用localStorage还是chrome.storage的代码。变量被附加到窗口中,以便全局可用。
if !!window.chrome and chrome.storage
window.storageType = ChromeStorage
else
window.storageType = LocalStorage
存储API
接下来,存储API,它使用了Coffeescript中的"Class"。目前还没有完全抽象化。我还有一些代码要处理从localStorage到chrome.storage的迁移。localStorage类是伪异步的。
class LocalStorage
# Gets a generic value from localStorage given a particular key
# Parses the JSON so it's an object instead of a string
@get: (key, callback) ->
value = localStorage.getItem(key)
value = JSON.parse(value)
callback(value)
# Synchronously gets the stuff from localStorage
@getSync: (key) ->
value = localStorage.getItem(key)
JSON.parse(value)
# Sets something to localStorage given a key and value
@set: (key, value) ->
value = JSON.stringify(value)
localStorage.setItem(key, value)
# Removes something from localStorage given a key
@remove: (key) ->
localStorage.removeItem(key)
class ChromeStorage
# Return all the tasks given the key
# At the moment the key is 'todo' for most calls
@get: (key, callback) ->
chrome.storage.sync.get key, (value) ->
value = value[key] || null || LocalStorage.getSync(key)
callback(value)
# Set all the tasks given the key 'todo' and the thing we're setting
# Usually a JSON array of all the tasks
@set: (key, value, callback) ->
params = {}
params[key] = value
chrome.storage.sync.set params, () ->
# Remove a whole entry from chrome.storage.sync given its key
@remove: (key) ->
chrome.storage.sync.remove key, () ->
# Listen for changes and run Views.showTasks when a change happens
if !!window.chrome and chrome.storage
chrome.storage.onChanged.addListener (changes, namespace) ->
for key of changes
if key == DB.db_key
storageChange = changes[key]
Views.showTasks(storageChange.newValue)
用法示例
最后,这里是我如何在代码中使用Storage API的示例。此方法保存一个新任务。DB.DB_key是一个变量,表示要在存储中使用的密钥。
# Sets a new task
# Receives name which is in the input
@setNewTask: (name) ->
# Only do this stuff if the input isn't blank
unless name == ''
# Sends the task to @createTask() to make a new task
newTask = @createTask(name)
# Get all the tasks
window.storageType.get DB.db_key, (allTasks) ->
# Adds that new task to the end of the array
allTasks.push newTask
# Save all the tasks
window.storageType.set(DB.db_key, allTasks)
# Show the tasks
Views.showTasks(allTasks)
GitHub存储库位于此处:https://github.com/humphreybc/super-simple-tasks
- 如何在构建node-webkit应用程序后获取外部资源
- 如何为生产构建angular2应用程序
- Grunt构建导致Angular应用程序在dist上崩溃
- 如何构建angular.js应用程序
- 如何使用Meteorjs构建实时应用程序
- 如何在dojo应用程序构建概要文件中加载json文件
- 如何在Windows上用javascript构建本机应用程序
- 为具有核心模块和子模块的应用程序构建Webpack
- 构建模块化谷歌地图应用程序
- 使用经久耐用的工具构建 Web 应用程序
- Javascript Sencha cmd 应用程序构建错误发生在执行此行时
- 使用 Grunt/Gulp 构建 SAPUI5 应用程序,并使用 ABAP Team Provider 部署 Eclip
- 如何为略有不同的不同版本的web应用程序构建代码
- 如何在ExtJS中构建无需鼠标即可工作的应用程序
- node.js可以选择性地引入到用普通PHP/js/CSS/HTML构建的web应用程序中吗
- 使用AngularJS应用程序为移动设备(iOS、Android等)构建本地应用程序的最佳方式
- 理论上是否有可能使用 chromium 的可安装网络应用程序 API 构建纯 JS bittorrent
- 全栈应用程序Gulp构建的输出/路径/结构策略
- 在Windows 8 Metro Javascript应用程序中构建特定的条件符号
- 在.net MVC应用程序中构建javascript