In the beginning, Javascript did not have a way to import/export modules. This is a problem. Imagine writing your app in just one file - it would b...
For further actions, you may consider blocking this person and/or reporting abuse
ES6 modules aren't asynchronous, at least not as they are in use right now most places. Put simply, unless you're using dynamic imports (see below), each import statement runs to completion before the next statement starts executing, and the process of fetching (and parsing) the module is part of that. They also don't do selective execution of module code like you seem to imply.
import {bar, baz} from './foo.js'
loads, parses, and runs all of './foo.js', then binds the exported entities named 'bar', and 'baz' to those names in the local scope, and only then does the next import statement get evaluated. They do, however, cache the results of this execution and do direct binding, so the above line called from separate files will produce multiple references to the single 'bar' and 'baz' entities.Now, there is a way to make them asynchronous called 'dynamic import'. In essence, you use
import
as a function in the global scope, which then returns a Promise that resolves to the module you're importing once it's fetched and parsed. However, dynamic import support is somewhat limited right now (IE will never support it, Edge is only going to get it when they finish the switch to Chromium under the hood, and UC Browser, Opera Mini, and a handful of others still don't have it either), so you can't really use them if you want to be truly portable (especially since static imports (the original ES6 import syntax) are only valid at the top level, so you can't conditionally use them if you don't happen to have dynamic import support).As a result of this, code built around ES6 modules is often slower than equivalent code built on AMD (or a good UMD syntax).
Hi Austin, thanks for the reply! I appreciate you taking a lot of time to write this.
According to this link, it says "ECMAScript 6 gives you the best of both worlds: The synchronous syntax of Node.js plus the asynchronous loading of AMD. ", and this article also says that " ESM is asynchronously loaded, while CommonJS is synchronous."
Regarding ESM speed, what I meant to say is that ESM creates static module structure (source, source), allowing bundlers to remove unnecessary code. If we remove unnecessary codes using bundlers like webpack/ rollup, wouldn't this allow the shipping of less codes, and if we ship less code, we get faster load time? (btw, just reread the article, I definitely didn't mention rollup usage. Will revise that).
There is a good chance I am wrong (still learning about JS modules) or interpreted what I read incorrectly (also likely, happened before), but based on what I've read, ESM is async and ESM in overall is faster because it removes unnecessary code. I really appreciate your comment - it forced me to look up more stuff and do more research!
Digging a bit further myself, I think I know why I misunderstood the sync/async point. Put concretely based on looking further at the ES6 spec, the Node.js implementation of CJS, and the code for Require.js and Alameda):
So, in a way, we're kind of both right. The loading and parsing for ESM modules is indeed asynchronous, but the execution of the code in them is synchronous and serialized based on the order they are imported, while for AMD, even the execution of the code in the modules is asynchronous and based solely on the order they are loaded.
That actually explains why the web app I recently converted from uisng Alameda to ESM took an almost 80% hit to load times, the dependency tree happened to be such that that async execution provided by AMD modules actually significantly cut down on wait times.
This is a notification to express my (many!) thanks for your superb explanation. This resolves all of my confusions about ES6 modules!
Can you please clarify?
Let's say we have three files:
Console output after run
node index.js
:It's clear that
index.js
andbar.js
share the same object fromobj.js
.Because
obj.js
is exporting an object literal. The first time you requireobj.js
the object is instantiated, and assigned memory allocation. Every time you require it, it's the same object, from memory. Ifobj.js
was exporting a function that returned an abject, well that would be different.Agree. But in this case the exported function will be the same for all modules (i.e. the function will not be copied for every import).
Right
Not like you should be changing modules anyways...
Do CJS imports copies the exported object? I think not. If you create an object in a module and export it using module.exports it is used for every import. Imports from other modules do not create new objects. They uses the same object.
Hello, may I translate your article into Chinese?I would like to share it with more developers in China. I will give the original author and original source.
Sorry for the late reply, definitely!
in this part, which you say can run in browser:
where do it get
my-lib
from?You can have local file that exports
func1
, say a js file 'my-lib.js' .Then your import becomes :
inside my-lib.js, have something like:
Another really good article, older, bug goes much more in-depth.
hacks.mozilla.org/2018/03/es-modul...
This is another good article. Good suggestion!
Thanks for this explanation! Very concise, well written, and well compared. :)
Is writing everything in one file really necessarily nightmarish..?
Haven't seen enough dependency hell and god-know-how..?
Much the reason people disfavor GOTO spaghetti.
Extreme invert. Excess amok.
Insane decoupling is not applicable: things are by nature coupled, inseparable.
Elements are each other coupled and constitute a blob of whole, much of unawarely implications.
.
Well realizing the underlying implementation is the only way to guarantee effectiveness and efficiency.
Still relevant in 2022 and really cleared things up for me 👏 Thank you!
I count myself lucky enough to see the wonderful answer 4 years later here since 2019.
Thanks for the article you shared with us and the discussions indeed sovle my problem.
I didn't know these definitions before this reading...
Thanks for the well wrote sharing, Igor!