-2

I cannot for the life of me figure out why async/await behaves the way it does.

Consider this example.

I want a function that does some db initialization, and returns me the database object when it is done.

var globalDb = null;

const IDB_DATABASE_NAME = "mydb";
const IDB_STORE_NAME = "mystore";
const IDB_VERSION = 1.0;

async function initDb() {
    var idbOpenDbRequest = window.indexedDB.open(IDB_DATABASE_NAME, IDB_VERSION);

    idbOpenDbRequest.onsuccess = function (event) {
            return event.target.result;
    };
}

(async () => {
    globalDb = await initDb();
    console.log("I should happen second")
    console.log(globalDb);
})();

Expected

  1. console.log("I should happen first")
  2. console.log("I should happen second")
  3. console.log(globalDb); //dumps the object to console

Actual

  1. console.log("I should happen second")
  2. console.log(globalDb); //undefined
  3. console.log("I should happen first")

I realize I am fundamentally misunderstanding something here. Please enlighten me why await does not work as I would expect. :)

JsFiddle

https://jsfiddle.net/p2jqyrou/2/

Ps. Forget that this is about indexedDb and that this example is extremely simplified - I don't think it matters for the topic of this question.

Kjensen
  • 12,447
  • 36
  • 109
  • 171
  • 2
    There is indeed some confusion about just how async/await works here. I'll try and provide and answer but in the mean time maybe [this](https://www.asyncdrink.com/blog/async-await-basics) will help? – Mathyn Sep 10 '19 at 11:04
  • you are awaiting `initDb()`, but you can't await `setTimeout` as it doesn't returns a promise, hence console logs in unexpected (actually it's expected) order and function return undefined as it hasn't returned anything. – Vaibhav Vishal Sep 10 '19 at 11:04
  • @TheReason he is returning stuff from `setTimeout` callback and expecting it to be the return for `initDb()`. @Kjensen it doesn't works like that. – Vaibhav Vishal Sep 10 '19 at 11:07
  • @VaibhavVishal I removed the setTimeout now, it was just illustrating a point about timing, which was stupid of me, as it adds complexity (and actually screwed my example up in this case). The fundamental question/problem is still the same: Why is nothing returned form the function - and why is the order of the console.log different than my expectation? – Kjensen Sep 10 '19 at 11:09
  • 1
    @Kjensen in order to get something from function you should return it first. Do you return anything from `initDb`? – The Reason Sep 10 '19 at 11:11
  • @TheReason You mean like "return event.target.result;"? – Kjensen Sep 10 '19 at 11:12
  • `globalDb = await initDb()` awaits the return value of `initDb` function. The `initDB` function has no return statement of its own, therefore it returns undefined. – mbojko Sep 10 '19 at 11:14
  • Still you are returning from callback of `onsuccess` but nothing is returned from `initDb()`. I can't explain any more why your expected order of `console.logs` is incorrect. Please read some documentation and stuff about timeout, promise, etc in js. – Vaibhav Vishal Sep 10 '19 at 11:15
  • @VaibhavVishal Mathyn understood perfectly my intention and provided and excellent answer. But thanks for your time anyway. – Kjensen Sep 10 '19 at 11:29

1 Answers1

3

So the problem is with your initDb function. I'll rewrite it for you and then explain why this version does work:

function initDb() {
    var idbOpenDbRequest = window.indexedDB.open(IDB_DATABASE_NAME, IDB_VERSION);

    return new Promise((resolve, reject) => {
        idbOpenDbRequest.onsuccess = function (event) {
            setTimeout(function () {
                console.log("I should happen first");
                resolve(event.target.result);
            }, 2000);
        };
    })
}

What I've done is wrap the onsuccess callback in a Promise. The async/await pattern in Javascript is fundamentally based around Promises. Either you return a Promise yourself or it wraps the result in a Promise (and immediately resolves it).

Because you did not return a Promise yourself it tried to wrap the return value (which was undefined) in a Promise. It then immediately resolved causing the async function to return.

With this updated code initDb is called which then returns a Promise which is only resolved after the connection has been made and after the timeout triggered.

Mathyn
  • 2,436
  • 2
  • 21
  • 33