It also doubles as a (very silly) rice cooker! Add a program to bring the pan to 230 F on slow intensity followed by a 2 minute timer. This will slowly simmer the water then stop cooking right after the water is all evaporated, which is exactly the process of dedicated rice cookers.
This is inaccurate, or at least misleading. Your code doesn’t begin executing until all of the modules are loaded so it doesn’t “make the call stack async” just because of the import system. Module loading that’s async from the point of view of user code is also supported, but it’s use is rare.
> Your code doesn’t begin executing until all of the modules are loaded.
This is inaccurate, or at least misleading.
This, or some aspect of it, is both possible and relatively common:
import foo from 'foo';
await foo.bar();
await Promise.all([
import('other'),
import('stuff'),
]);
// Admittedly this is less common but also valid!
import yet from 'more-stuff';
The asynchrony of ESM was controversial before it even became a standard. But it’s necessary because it allows network I/O. And most of the above patterns being relatively common is one of the major use cases for bundling, because it also introduces an indefinite waterfall.
In terms of rarity, dynamic import calls are already quite common for “lazy”/“suspense” or their equivalents in quite a lot of real world code, and likely to become moreso with React Server Components and other similar solutions deferring to server rendering.
Yes, an import statement is [semantically] blocking. But even so it’s important to know that it’s performing async I/O.
You only have to `await foo.bar()` if foo.bar was an async function already, the module system is irrelevant. You would still need to await it even if it was `require()`'d in.
Of course these have to be awaited, at this point you're explicitly trying to load new code while the program is running. It's no different than any other kind of async IO.
> import yet from 'more-stuff';
I assume this is included to imply that loading `yet` is blocked by the `await Promise.all` above it to show that import statements can run after module resolution. If this was your intent you are mistaken, that import statement is still resolved before execution begins.
// main.js
console.log('a')
await new Promise(res => setTimeout(res, 1000))
console.log('b')
import { foo } from "./foo.js";
// foo.js
export function foo() {
}
console.log('c')
Results in
c
a
[one second pause]
b
> Yes, an import statement is [semantically] blocking. But even so it’s important to know that it’s performing async I/O.
No, it really isn't. From the POV of the application code it's irrelevant. This is trivially proven by the existence of module bundlers which convert non-dynamic `import` statements into one big file that doesn't do anything asynchronous to initialize.
> You only have to `await foo.bar()` if foo.bar was an async function already, the module system is irrelevant. You would still need to await it even if it was `require()`'d in.
You cannot do that. Top-level await is forbidden because CJS require is explicitly synchronous.
> Works just fine, no `await` necessary.
I typed all of that on a phone so I erred on the side of brevity, but suppose either the Promise.all or the awaited imports depended on some result from importing foo.
> I assume this is included to imply that loading `yet` is blocked by the `await Promise.all` above it to show that import statements can run after module resolution. If this was your intent you are mistaken, that import statement is still resolved before execution begins.
I was trying to show that import statements are blocked by prior awaits. I’m not sure what you’re trying to show, but you’d need to log output after the import from foo.js to see how the asynchrony works for that import.
> No, it really isn't. From the POV of the application code it's irrelevant. This is trivially proven by the existence of module bundlers which convert non-dynamic `import` statements into one big file that doesn't do anything asynchronous to initialize.
Compare that to a non-bundled but otherwise similarly optimized app and look at the waterfall.
Subtrees, instead of submodules, are meant to be super-cool - and I'd love to try them, but I'm still far too wedded to existing git tooling (namely GitKraken) where there's still no support for subtrees.
I was trying to write a program using midi last year and was surprised by the lack of any libraries to work with it. Then I looked up the spec and was able to get all the functionality I needed with 10 lines of code interacting with /dev/midi. Incredible how powerful such a simple interface is.
That’s why the comparison is apt. “Cars are were bad for cities” isn’t a remotely hot take, and yet nobody claims that the invention of the car was a net-negative for the world.