You would normally provide the db.version(x).stores({...}) each time you open the database, no matter if it needs to be created, upgraded or just being opened. By providing this info, you will get immediate access to your tables directly on the db object (accessing for example db.friends.toArray() without waiting for db.open() to finish) as samplified below:
var db = new Dexie("friendsDB");
db.version(1).stores({friends: 'id, name'});
// Here you can just access db.friends without waiting for db.open()
db.friends.toArray()
.then(friends => console.table(friends))
.catch(err => console.error(err));
However, it is also possible to open a database dynamically - that is, open an exising database without knowing its tables or indexes. To do that, you just omit the version().stores() part. Just be aware that you wont be able to access tables directly on the db instance and you don't get the magic auto-creation of the database. Tables meed to be accessed through the tables property and table() method, and only after db.open() has completed.
new Dexie("friendsDB").open().then(db => {
console.log("Table names: " + db.tables.map(t => t.name));
return db.table("friends").toArray();
}).then(friends => {
console.table(friends);
}).catch(err => console.error(err));