# Using async / await with dynamic import() for ES6 modules

I am experimenting with the best way to standardise my dynamic import() expressions when importing javascript modules.

import() returns a promise, so, to handle the asynchronous steps after theimport() expression, I can use either:

• .then() syntax; or
• async / await syntax

Whilst I am quite familiar with the older XHR2 approach and somewhat familiar with ES2015 .then() syntax, I am less familiar with async / await syntax.

I understand that I can only use await inside a function which has been declared or assigned with async.

But I am trying to understand why Approach 1 works.

Approach 1:

(async () => {

let myImportedModule = await import('/path/to/my-module.js');

myImportedModule.myFunction1();
myImportedModule.myFunction2();

})();


But Approach 2 does not.

Approach 2:

(async () => {

await import('/path/to/my-module.js');

myFunction1();
myFunction2();

})();


Clearly I have something wrong, but I thought Approach 2 would be the async / await equivalent of this snippet (using .then() syntax):

import('/path/to/my-module.js')

.then((myImportedModule) => {

myImportedModule.myFunction1();
myImportedModule.myFunction2();

});


but that it would enable me to access myFunction1 and myFunction2 directly, without needing to give a name to the resolved Promise.

• It's the opposite. Approach 1 is the equivalent of the then version. Otherwise the meaning would be completely different. To understand this, think about how names are resolved and how they can be shadowed. Feb 24 '20 at 17:18
• But that's not how modules work in general. Maybe you want a destructuring assignment (const {f, g} = await import(...);)? If you want them at module scope, that's highly problematic. Feb 24 '20 at 21:20
• You may also be interested in github.com/tc39/proposal-top-level-await, which you can start using now if you use TypeScript or Babel. Feb 24 '20 at 21:25
• Thanks for all your help, @AluanHaddad. This is a key statement: "But that's not how modules work in general." I've reconciled myself to importing an object with properties, rather than individual variables whenever I use dynamic import(). Feb 24 '20 at 23:37
• Glad to be of service. I think the ergonomics don't bother me as much since I usually just export default expression, a habit I got into because of loader-interop issues and then became enamored of. I fully understand why many prefer to export multiple bindings though. Feb 25 '20 at 0:45

Approach 2 does not work because accoring to MDN:

import '/modules/my-module.js';


Is how you import a module for Import a module for its side effects only

Import an entire module for side effects only, without importing anything. This runs the module's global code, but doesn't actually import any values.

So, await import('/path/to/my-module.js'); won't actually import your myfunction1 and myFunction2 for you to use them, however, if you put an IIFE in there, it will be called.

If you don't want to use long names to call your function, you can destructure them :

(async () => {

const { myFunction1, myFunction2 } = await import('/path/to/my-module.js');

myFunction1();
myFunction2();

})();


Or, call them in my-module.js and just import it and they will get called.

See the answers here for es6 import for side effects meaning.

• Well explained answer. Thank you. Feb 24 '20 at 23:35