14
\$\begingroup\$

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();

})();

Additional Notes:

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.

\$\endgroup\$
6
  • \$\begingroup\$ 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. \$\endgroup\$ Feb 24, 2020 at 17:18
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ Feb 24, 2020 at 21:20
  • 2
    \$\begingroup\$ 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. \$\endgroup\$ Feb 24, 2020 at 21:25
  • 1
    \$\begingroup\$ 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(). \$\endgroup\$
    – Rounin
    Feb 24, 2020 at 23:37
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ Feb 25, 2020 at 0:45

2 Answers 2

14
\$\begingroup\$

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.

\$\endgroup\$
0
0
\$\begingroup\$

for some reason this wasn't working for me:

const {capitalize} = await import(/* webpackChunkName: "lodash" */'lodash').default

but this is:

const {capitalize} = await import(/* webpackChunkName: "lodash" */'lodash')
    .then(module=>module?.default);

note: i'm using Webpack's experimental topLevelAwait option set to true

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Welcome to Code Review! This does not really answer the question. If you have a different question, you can ask it by clicking Ask Question, though only if you have working code. This statement would be appropriate as a comment, though you will need to earn 50 reputation points first... \$\endgroup\$ Apr 14, 2022 at 16:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.