Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

There should be an async version - deferAsync? #29

Open
mitschabaude opened this issue Mar 9, 2024 · 6 comments
Open

There should be an async version - deferAsync? #29

mitschabaude opened this issue Mar 9, 2024 · 6 comments

Comments

@mitschabaude
Copy link

mitschabaude commented Mar 9, 2024

This proposal adds a cool new feature (fetching/linking a module without executing immediately) but denies that feature to all modules which use top-level await (TLA).

This clashes with the current ESM model where modules that use TLA are treated just like any other modules, anywhere: import statements work normally for them and import() is async already. ESM established a world where modules can safely use TLA without downsides.

This proposal breaks that model. It makes modules that use TLA worse than other modules because there is no way to fetch them while defering their execution.

This seems unnecessary, because there could just be an async version of defer, which allows you to defer execution of an entire TLA module. Many consumers don't care about the described "problem" that exposing something becomes an async function; for them the async version of defer would be the better version, because it would defer a larger part of the execution.

I propose:

import deferAsync * as myModule from "mypath"

Let's examine possible behaviors:

  • myModule is a promise itself, and executed only when it is awaited
    • this seems a bit weird, because awaiting a promise can usually not trigger anything in JS
  • all properties of myModule are promises; the module is executed only when one of them is accessed.
    • this seems natural, and is very similar to defer, where myModule basically becomes a smart proxy for the module

To reiterate, deferAsync would be a strictly better version of defer for all consumers that are fine with getting promises.

@mitschabaude
Copy link
Author

In light of #28, there could also be import.deferAsync('<specifier>')

@ljharb
Copy link
Member

ljharb commented Mar 9, 2024

typically, a promise is a placeholder for the future value of work that has already begun, so I think it'd be very surprising and weird and unidiomatic to have awaiting it actually cause anything to happen.

@mitschabaude
Copy link
Author

typically, a promise is a placeholder for the future value of work that has already begun, so I think it'd be very surprising and weird and unidiomatic to have awaiting it actually cause anything to happen.

yeah I wrote that as well. but having a bunch of properties that are promises and having the property access cause the work to happen seems fine (same as proposed behavior for defer)

@nicolo-ribaudo
Copy link
Member

nicolo-ribaudo commented Mar 10, 2024

Oh the web you can already get this behaviour, by combining modulepreload and dynamic import:

<link rel="modulepreload" href="./that/module.js">
later(async () => {
  let mod = await import("./module.js");
});

Except for some specific circumstances, such as devices with very load bandwidth, when you call dynamic import the module will have already been fully loaded (including its dependencies), parsed and linked.

To reiterate, deferAsync would be a strictly better version of defer for all consumers that are fine with getting promises.

No, most of those consumers should just use dynamic import, since it allows skipping more work (i.e. loading/parsing).

The main motivation of this proposal is that, unlike dynamic import, allows deferring synchronously.

@mitschabaude
Copy link
Author

@nicolo-ribaudo thanks for the answer. This is a good point.

I still feel deferAsync would be a natural addition, and a much "nicer" way to declare a lazy dependency than the html tag (also for the reason given in #15). Also, note that the preload tag isn't really accessible to library authors - my hope is that deferAsync would be, because bundlers would respect it.

But I accept that deferAsync doesn't add anything which is fundamentally impossible right now, while defer does.

@silverwind
Copy link

As for syntax, I suggest using import attributes, see #5 (comment).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants