Dynamic Imports and Full Support & compatibility with top-level await
The top-level await explained
Since the latest version of NodeJs and V8 in what they were announcing full support and compatibility with top-level await proposal of tc39, there was a storm of diverse opinions around the Internet. The most popular was the gist of Rich Harris called by the V8 team as the infamous gist, that in the first term were explaining in detail how and why such a braking change feature introduced in the language could be a footgun. But he is not the only one active in the concern of the impact of this functionality. Recent posts on reddit caused a revolution of comments in different directions, some of them pointing the lack of clarification of the real use cases of the top-level await in real world situations.
A detailed explanation of the top level await feature if already published in the tc39.es website and the official announcement of the V8 team. You can also visit the [note for the proposal for top-level await in the GitHub official repo of tc39] (github.com/tc39/proposal-top-level-await)
But, in terms of code, what is the real change?
On very simple words, this:
(async function (){
await myAwaitedFunctionCall();
})()
Changes to this:
await myAwaitedFunctionCall();
Before the top-level await feature
Who is supporting the top-level await feature?
According to the current V8 feature support table, it seems like only Chrome, but NodeJs has support from the version 14.8.0 according to MDN docs
How can the top-level await interact with QCObjects syntax
Since the 2.3 version of QCObjects you can call imports either using the Import function (available in the framework) or the import statement (available in the JavaScript language)
The syntax for both is so similar, with a small difference:
// Import call syntax using Import function (available in the framework)
Import (url, [ready callback] , [url is external true or false]);
// import call syntax using import statement (available in the language)
import url;
import foo from url;
One of the cool things that using a top-await allows is to prevent unwanted parallel execution of the script contents in the url to be imported.
For instance,
If I have two modules to be imported in a main script:
// main.js using QCObjects Import function
Import ("module1");
Import ("module2");
With QCObjects (without top-level await) we can yet alternatively use the ready callback or the promise returned by the function to prevent parallel execution:
//Using QCObjects with the callback
Import ("module1", ()=>{
Import ("module2")
})
// Using QCObjects with the promise
Import ("module1").then (
()=> Import ("module2")
);
On the other hand, using the import statement we could achieve the same result but using a bit uglier code:
(async function (){
await import "module1";
})()
(async function (){
await import "module2";
})()
What top-level await brings us is a simplified syntax in this case, as you don't need to enclose the imports into an async function. This is also called imperative import
// imperative import statement
await import "module1";
await import "module2";
And you can also do it with the QCObjects Import function:
// imperative Import function call
await Import ("module1");
await Import ("module2");
A Quick Note:
Needless to say the Import function of QCObjects was designed for compatibility purpose across platforms and it is working since the promises were released for all browsers in ECMA2015. The new import statement is a proposal for the ECMA2020 what is currently in process of adoption in browsers, but is currently available in most of them. Another thing to note is that import statement is only working into modules, while the Import function of QCObjects is working even into traditional text scripts as well as into modules, so you can make imports even if you are not working with a bundler, and even if you are not working with modules. That, between other reasons, is why QCObjects Framework also implements the Package concept.