-
-
Notifications
You must be signed in to change notification settings - Fork 191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Workaround for initialization failure on Safari 7 #144
Comments
One additional change is needed. There are two use cases:
The above code only covers the first use case. The following code covers both. This code emits an initialization event if it's never been created, as well as if it already exists. You can listen for the IndexedDBShimInit (or whatever you want to call it) event to open the database for transactions. I tested the pattern below on Safari 7, Firefox 30, Chrome 35 and Chrome Canary for both use cases: sysdb.transaction(function(tx){
tx.executeSql("SELECT * FROM dbVersions", [], function(t, data){
console.log("IndexedDB Shim INITIALIZED!");var event = new Event("IndexedDBShimInit"); window.dispatchEvent(event);
}, function(){
// dbVersions does not exist, so creating it
sysdb.transaction(function(tx){
tx.executeSql("CREATE TABLE IF NOT EXISTS dbVersions (name VARCHAR(255), version INT);", [],
function(){ console.log("IndexedDB Shim dbVersions table created!");var event = new Event("IndexedDBShimInit"); window.dispatchEvent(event);},
function(){
idbModules.util.throwDOMException("Could not create table __sysdb__ to save DB versions");
});
});
});
}, function(){
// sysdb Transaction failed
idbModules.DEBUG && console.log("Error in sysdb transaction - when selecting from dbVersions", arguments);
}); |
Hello andygup, and thanks for the workaround. This seems to work like a charm in iOS now. However, I intend to run my code in both Android and iOS, and just listening to the IndexedDBShimInit event is a problem: in Android, the database is initialized before I can register any listeners. What I have done is to set a global variable (i.e. window.INDEXEDDB_STARTED) at the same time that the IndexedDBShimInit event is dispatched. This allows me to know whether the database was initialized before I had time to register any listeners. However, I admit that this is a rather ugly solution (I'm not much of an expert with JS), so I'd like to ask - would there be a more elegant way of achieving the same purpose? |
@davidmartingonzalez I'm not aware of a more elegant solution at this time. The problem is a typical web application life-cycle issue -- things simply have to load in the right order for everything to work correctly. Good idea on the global. I have some additional suggestions for folks doing both Android and iOS based on additional testing:
Here is the updated 'hack' for the shim that supports both Android and iOS, and additionally it now works correctly with multiple reloads: // Change default size to avoid Safari quota bug:
// https://github.com/axemclion/IndexedDBShim/issues/115
var DEFAULT_DB_SIZE = 12 * 1024 * 1024;
if (!window.openDatabase) {
// If Web SQL isn't available we still need to send an init event!
console.log("IndexedDB Shim Web SQL not supported!");var event = new Event("IndexedDBShimInit"); window.dispatchEvent(event);
return;
}
// The sysDB to keep track of version numbers for databases
var sysdb = window.openDatabase("__sysdb__", 1, "System Database", DEFAULT_DB_SIZE);
sysdb.transaction(function(tx){
tx.executeSql("SELECT * FROM dbVersions", [], function(t, data){
console.log("IndexedDB Shim INITIALIZED!");var event = new Event("IndexedDBShimInit"); window.dispatchEvent(event);
}, function(){
// dbVersions does not exist, so creating it
sysdb.transaction(function(tx){
tx.executeSql("CREATE TABLE IF NOT EXISTS dbVersions (name VARCHAR(255), version INT);", [],
function(){ console.log("IndexedDB Shim INITIALIZED!");var event = new Event("IndexedDBShimInit"); window.dispatchEvent(event);},
function(){
idbModules.util.throwDOMException("Could not create table __sysdb__ to save DB versions");
});
});
});
}, function(){
// sysdb Transaction failed
idbModules.DEBUG && console.log("Error in sysdb transaction - when selecting from dbVersions", arguments);
}); And, then in your main application you can set up the listener similar to this psuedo-code: <script>
window.addEventListener("IndexedDBShimInit",load);
function load(){
// load database and start using it here.
}
</script>
<script src="<sub-directory>/IndexedDBShim.js"></script> |
@davidmartingonzalez I do know of several different approaches that would help alleviate this problem. However they involve changing the architecture of the shim. Those changes would need to be socialized with the owners of the shim as well as the user community (those who have already forked it) to see if they open to a new architecture and potentially breaking changes. In an attempt to clarify the issues as I'm seeing them, here are several technical use cases for discussion: Use case 1 - Ability to use the shim with Safari and Chrome (Android). When attempting to use the same pattern for loading and working with the shim in both Chrome and Safari, Safari appears to have a different approach to loading the library that is causing life-cycle issues and essentially the shim fails to work. Use Case 2 - Ability to listen for initialization events from the shim. Developers should be informed if the following conditions are met:
Use Case 3 - Ability to restart the application and have the shim re-initialize correctly. I'm making a distinction between the initial load that creates the database and reloading the application and initializing a database that already exists. Use Case 4 - Allow for graceful detection of initialization failures. By implementing a callback architecture or an event-driven architecture, developers can easily detect failures and handle them appropriately. The current architecture seems to require tricky web app detection code and life-cycle specific script loading to determine if the shim has initialized. And, here is another potential approaches on changes to the shim: Suggestion 1 - remove the shim's ability to self initialize. Instead allow the shim to be instantiated, for example: var shim = new IndexedDBShim(); This will offer precision control over the life-cycle of shim. Suggestion 2 - use a callback in the constructor. The callback should return a boolean and any initialization errors. Example: var shim = new IndexedDBShim(function(success,error){ ... } |
In Safari v7, under certain conditions the library may not be initialized before you try to call
indexedDB.open()
. This can happen if you need the database open immediately when the page is loaded. The issue may be related to #115The errors you may see include:
could not prepare statement (1 no such table: dbVersions)
DOMError
One workaround is to:
window.addEventListener("IndexedDBShimInit",load);
The text was updated successfully, but these errors were encountered: