I am trying to use the following statement:
import { defer } from '@types/q';
...
var deferred = defer();
...
return deferred.promise;
Now I am getting a Runtime Error stating:
Cannot find module “@types/q”
I have tried adding it to my app.module.ts file and as soon as I add it my ngModule fails to compile. I am unsure how to resolve this issue. Where do I have to import it so that it will work?
I think I have found out how to handle this issue. I was trying to add something that I think was deprecated. If I async before the function it seems to allow me to use the .then .catch
async connectToDb() {
I think async
/await
make code less readable. What is the initial source of the future here? What initiates the asynchronous operation?
This is similar to my post about Databases. I want to have my app open a screen only if the user is setup correctly.
If the user is setup correctly it will change the homepage to a different page with more functionality. I can make it work but I have a setInterval with code waiting for it to update a “isConnected” variable for the database.
I am trying to figure out how to use the async or await so that I do not have to use a hack to stop it from reading from my db variable before it has been established.
I prefer to design this potential problem away by how things are exposed. Can you explain what “my db variable” is, what the process of “establishing” it consists of, and who the first “it” is?
Here is the code that I assume should be working:
this.db.connectToDb().then(() => {
console.log("Connected to DB?");
this.md.setDeviceWithArray(this.db.getInfo());
if(this.md.getDevice().length > 0){
//The device should have info which would allow for the root page to change.
this.navCtrl.setRoot(InfoPage);
}
})
.catch(error => {
console.log("ERROR: " + JSON.stringify(error));
});
The above code doesn’t wait until after db.connectToDb is finished before running. This was the whole point of doing a .then statment(in what I think it is supposed to do).
This is my hack to get around it:
this.theInterval = setInterval(() => {
this.timerToken++;
if(this.db.checkIfDbIsConnected()){
//this.md.setDeviceWithArray(this.db.getInfo());
if(this.md.getDevice().length > 0){
this.navCtrl.setRoot(InfoPage);
console.log("INITIALIZED DB");
clearTimeout(this.theInterval); //stop it once initialized
}
}
else{
console.log("RUNNING " + this.timerToken);//Variable to track how many times it runs
}
}, 100);
The above code runs once and it works. It only needs a fraction of a second before the database variable is ready to be used.
My database is initialized as follows:
async connectToDb() {
if(!this.isConnectedToDB){
this.sqlite.create(this.options)
.then((db: SQLiteObject) => {
this.db = db;
this.isConnectedToDB = true;
//IF you move the below statement out of here then the db variable will not be initialized
//before you can use it to execute the SQL.
})
}
}
This code works…but doesn’t perform how I would expect it to. I assumed that both variables would be set before the then statement in the first example mentioned would happen. But they go head and do not wait for the function to finish.
I assume that I do not understand how async and the .then statement works.
If you aren’t doing fancy SQL queries and joins, which is the case for probably 95% of mobile apps, you might want to look into using ionic-storage, as the API is much simpler and, unlike direct interaction with SQLite, it works just fine in browser environments as well.
That being said, here are some rules I have made for myself when dealing with asynchronous code. In this case, connectToDb()
falls into the third category, so make the first word of it be return
(and I would get rid of async
).
I also don’t like “gatekeeper” variables like isConnectedToDB
. Everything that’s accessible should always be in a usable state. This thread describes an idiom that you might adapt, where db
is not exposed as a raw property, but rather as a Promise
itself.
In the long run, however, I think the safest, cleanest, and clearest way to do any of this is to never expose any details of storage implementation outside of service providers, so this whole connectToDb()
shouldn’t be callable from outside, if it even exists once we’re done refactoring things. When it comes to the notion of conditionally setting root pages based on external events such as user authentication state, I use this pattern, in which your app component doesn’t need to know or care how user authentication happens, just when it has.