Closed xxoo closed 6 years ago
Edit: I may have confused the imported value: module binding / module record, see other replies)
I suppose this is the expected behavior due to the semantics of promises: the value passed to the .then
handler is never a promise.
This effectively means that you cannot import promises from other modules (they will always be resolved).
I'd say that it is better to keep the current promise semantics. A less confusing workaround to changing the semantics is to just use a function instead of exporting a bare promise:
2.js
export default async function() {
[m3, m4] = await Promise.all([import("./3.js"), import("./4.js")]);
return `2.js with ${m3.m3} and ${m4.m4}`;
}
You can use it as:
1.js
import("./2.js")
.then(m2 =>{
const p = m2.default();
console.log(`pending promise`);
return p;
})
.then(result => console.log(result)); // 2.js with 3.js and 4.js
Basically, if a module exports a Promise, it means that is not usable until this promise is resolved. If you should be able to use before, then let the consumer create the promise when he actually needs it.
@demurgos thanks for pointing out. but i mean import() should wait only if the whole module is a promise. that's not really necessary but can make your code more clear.
I think what you are looking for is top-level await.
@matthewp sure, that's another good thing to have. but i guess async functions may lead performance issue or we don't need the keyword otherwise. making all top level scope async might be risky at this time.
in this case perhaps we don't really have to use async functions. always write one more then(v => v.default)
after import()
and always use export default
should be enough. like
1.js
import('./2.js').then(v => v.default).then(m => console.log(m));
2.js
export default Promise.all([
import('./3.js').then(v => v.default),
import('./4.js').then(v => v.default)
]).then(([m3, m4]) => `2.js with ${m3} and ${m4}`);
3.js
export default '3.js';
4.js
export default '4.js';
@xxoo Actually, there's a pretty good chance that async/await
can be optimized so that it's faster than using Promises directly.
The reason for the keyword is to indicate which function calls are asynchronous and which are not, because that affects the behavior of the functions. It's done for semantic reasons, not performance reasons.
import()
gives you a Promise for a ModuleRecord, not the default export. Unless you have a named export “then”, that’s a function, exported promises won’t be implicitly awaited; they’ll just be properties on the ModuleRecord.
@Pauan that's really good to know. but i didn't compare async functions to promises, i did compare them to normal functions. if we want to make a top level await call, we need the top level scope to be async. i just wonder, if there is no issue, why that's not done by default.
This thread does not appear to be a bug report with the specification, so let me close it. If people still want to continue discussing things in the closed thread, that's fine.
@ljharb good god u are the man! problem solved! the ModuleRecord does't need to be a promise, it just need to be thenable.
1.js
import("./2.js").then(m => console.log(m)); //2.js with 3.js and 4.js
2.js
export function then (resolve, reject) {
Promise.all([import('./3.js'), import('./4.js')])
.then(([m3, m4]) => resolve(`2.js with ${m3.m3} and ${m4.m4}`));
}
3.js
export let m3 = '3.js';
4.js
export let m4 = '4.js';
@domenic it was just a suggestion or feature request. but not any more. thanks you and any one who watched it. may your code be strong clear and fast.
the
module
statement in 2.js is like the cmdmodule.exports = something
or amdreturn something
to export a top level value.in this case when
import()
received a promise as module, it will keep waiting till the promise chain is resolved or any of them is rejected1.js
2.js
3.js
4.js