javascriptfirefoxasync-awaitindexeddb

top-level await in a module prevents `onload` from firing


I'm seeing that the load event won't fire if I await for an IndexedDB opening at the top level in an indirectly loaded module.

If I remove the await, the load handler is called as expected. If I keep the await but replace the openDB call with a dummy promise (like Promise.resolve(42)), the load handler is called as expected.

What is going on, and how can I debug this?

index.html:

...
<script type="module" src="js/ui_index.js" type="javascript/module"></script>
...

(it also contains an importmap, so all the imports work correctly)

ui_index.js:

import * as db from "database";
...
window.addEventListener('load', () => console.log('onload'));
console.log('ui');

database.js:

import { openDB } from "lib/idb";

//         ↓↓↓↓↓ *** THIS AWAIT ***
const db = await openDB("my-database-name", 4, {

    upgrade(db, old_ver, new_ver, tx) {
        console.log(`db.upgrade ${old_ver}→${new_ver}`);
    }
}

console.log('db:', db);

The idb module above is a promises-based IndexedDB wrapper by Jake Archibald.

Console output with await:

db.upgrade 4→5
db: Proxy { <target>: IDBDatabase, <handler>: {…} }
ui

Console output without await:

db: Promise { <state>: "pending" }
ui
onload
db.upgrade 5→6

(The db.upgrade line, of course, is only present if I increment the DB version in the openDB call. It does not affect the onload behavior).

I am testing this in Firefox 120 and have not tried other browsers; I'm building a small web app for in-house use which will only be used with Firefox.


Solution

  • My guess is that you do the await in the script body instead of declaring a function that does the await, this postponed the attaching of onload event listener, I believe it is still fired but before your event listener is attached.

    May I suggest you something like this:

    database.js:

    import { openDB } from "lib/idb";
    
    export default async function open() {
            const db = await openDB("my-database-name", 4, {
                upgrade(db, old_ver, new_ver, tx) {
                    console.log(`db.upgrade ${old_ver}→${new_ver}`);
                }
            }
            console.log('db:', db);
    }
    

    ui_index.js:

    import open from "database";
    window.addEventListener('load', () => console.log('onload'));
    console.log('ui');
    open();