I think that if an export is statically async that the promise should hold up resolving that module as ready. When resolving the current dependency graph.
On Apr 22, 2017 10:50 AM, "Andrea Giammarchi" <[email protected]> wrote: > Cyril the discussion is now rather about about asynchronous export. > > However, what you linked is not a polyfill for import, that's more like a > half backed require. > > The polyfill for dynamic import where you actually use `import(path)` as > specified on stage 3 is here: > https://github.com/WebReflection/import.js > > The universal attempt to add `.import()` as CommonJS module is here: > https://github.com/WebReflection/common-js > > Latter does what you wrote but on both client and server (it also probably > resolves relative paths in a slightly different (more accurate?) way. > > That pattern never convinced CommonJS chaps that believes nobody wants > asynchronous requires in this world (I actually do as much as I want > asynchronous exports too ^_^) > > Regards > > > > On Sat, Apr 22, 2017 at 3:41 PM, Cyril Auburtin <[email protected]> > wrote: > >> If the discussion is about a polyfill for import() >> <https://github.com/tc39/proposal-dynamic-import> (not the static import) >> >> it's not too hard: https://gist.github.com/caub/4 >> 58cfe944f8abcf7b1aec608d0a878cc >> >> ```js >> (async()=>{ >> const [Stuff, {foo, bar}] = await Promise.all(['./x', >> './y'].map(require)); >> // .. >> })() >> >> >> ``` >> >> 2017-04-22 16:31 GMT+02:00 Andrea Giammarchi <[email protected] >> >: >> >>> > Why not just allow `export await` in all export syntactic forms? >>> >>> that would work for me, and it would be like my initial, and second, >>> example: `export default await Promise.all(...).then(...)` >>> >>> however, just to better understand what you're up to, I wonder if the >>> module would be held, in a non blocking way, until all asynchronous exports >>> have been resolved (desired) as opposite of introducing complexity for >>> hybrid modules where you have to await everything to be sure it won't break >>> (shenanigans) >>> >>> TL;DR unless the following would be possible too, please consider making >>> modules available only once fully resolved through their exports >>> >>> ```js >>> import await * as module from './module.js'; >>> ``` >>> >>> Regards >>> >>> >>> >>> >>> On Sat, Apr 22, 2017 at 3:08 PM, Matthew Robb <[email protected]> >>> wrote: >>> >>>> I know you probably didn't want things to go this direction in the >>>> conversation but this made me think up a generic way to do this. Why not >>>> just allow `export await` in all export syntactic forms? This would not be >>>> the same as top level await but a signal that the export will be the result >>>> of an asynchronous operation that follows the await. >>>> >>>> Then you could potentially do `export default await (async ()=>{ >>>> >>>> })();` >>>> >>>> On Apr 21, 2017 3:10 PM, "Bradley Meck" <[email protected]> wrote: >>>> >>>> > how's that different from a Promise ? >>>> >>>> `later` is not const and could change over time. Could even be set via >>>> something like: >>>> >>>> ``` >>>> setInterval(() => later = Date.now(), 1e3); >>>> ``` >>>> >>>> On Fri, Apr 21, 2017 at 2:00 PM, Andrea Giammarchi < >>>> [email protected]> wrote: >>>> >>>>> > let later; >>>>> > export default {then(notify) { if (ready) notify(later); else >>>>> queue(notify); }} >>>>> >>>>> how's that different from a Promise ? >>>>> >>>>> Don't get me wrong, I have a module [1] that does that already (use a >>>>> symbol as key and that's it) but yet for an importer, if that has to be >>>>> handled like a Promise, then why not just a Promise ? >>>>> >>>>> This is the bit I don't get. >>>>> >>>>> Thanks >>>>> >>>>> [1] https://github.com/WebReflection/broadcast#broadcast-- >>>>> >>>>> >>>>> >>>>> On Fri, Apr 21, 2017 at 7:38 PM, Bradley Meck <[email protected]> >>>>> wrote: >>>>> >>>>>> > how asynchronous export helps here ? >>>>>> >>>>>> >>> I cannot think about a single use case for wanting that: it's >>>>>> not usable from within the module, it won't be usable outside unless >>>>>> checked via ... an interval ? >>>>>> >>>>>> As stated in previous email: >>>>>> >>>>>> >> The previous email was stating there are use cases for updating >>>>>> exports. >>>>>> >>>>>> If you are updating exports that in general means live bindings / >>>>>> asynchronous work. >>>>>> >>>>>> > already covered by `export default new Promise(async () => {})` , >>>>>> right ? >>>>>> >>>>>> Kind of, this sacrifices live binding since `default` can only ever >>>>>> have 1 value. Something could use a thenable to export multiple values >>>>>> over >>>>>> time however similar to a live binding: >>>>>> >>>>>> ``` >>>>>> let later; >>>>>> export default {then(notify) { if (ready) notify(later); else >>>>>> queue(notify); }} >>>>>> ``` >>>>>> >>>>>> > how is the module consumer supposed to know when these exports are >>>>>> ready? >>>>>> >>>>>> > if it's an event emitted, libraries trusting the event that already >>>>>> happened will never know, so we are back to polling, which is a very bad >>>>>> approach, IMO, and if the solution is a Promise then it's covered >>>>>> already. >>>>>> >>>>>> Please read my previous email: >>>>>> >>>>>> >> The answer is no pattern has been standardized so it depends on >>>>>> your proposed solution. A `then()`-able is already in spec and seems >>>>>> like a >>>>>> possible choice (though I wouldn't use a Promise); top level await could >>>>>> be >>>>>> another but blocks the module graph. TDZ poll/checking on imports could >>>>>> be >>>>>> another (though not-preferable) solution. I am sure we could bikeshed >>>>>> other >>>>>> approaches. >>>>>> >>>>>> > so if two importers happen at different times the second importer >>>>>> can compromise with undesired features the first one or vice-verssa? >>>>>> >>>>>> No, ESM modules are only evaluated once. Such checks are most likely >>>>>> done up front. However, enabling a debugger for example might cause a new >>>>>> set of exports to be loaded/exported. >>>>>> >>>>>> > So, like I've said, I don't see real-world scenarios for exported >>>>>> modules that changes without notice. >>>>>> It looks unpractical and undesired. >>>>>> >>>>>> As stated in previous email: >>>>>> >>>>>> > Exporting asynchronously doesn't provide any coordination point ... >>>>>> >>>>>> The rest of my email(s) have been talking about coordination. >>>>>> >>>>>> On Fri, Apr 21, 2017 at 1:28 PM, Andrea Giammarchi < >>>>>> [email protected]> wrote: >>>>>> >>>>>>> > It could be something that is being mocked/spied upon. >>>>>>> >>>>>>> how asynchronous export helps here ? >>>>>>> >>>>>>> >>>>>>> >>>>>>> > It could be part of a circular dependency and so the modules do >>>>>>> get a hold of eachother without finishing evaluation. >>>>>>> >>>>>>> already covered by `export default new Promise(async () => {})` , >>>>>>> right ? >>>>>>> >>>>>>> >>>>>>> >>>>>>> > It could be that it lazily/async populates its exports due to >>>>>>> costs. >>>>>>> >>>>>>> how is the module consumer supposed to know when these exports are >>>>>>> ready? >>>>>>> >>>>>>> if it's an event emitted, libraries trusting the event that already >>>>>>> happened will never know, so we are back to polling, which is a very bad >>>>>>> approach, IMO, and if the solution is a Promise then it's covered >>>>>>> already. >>>>>>> >>>>>>> >>>>>>> >>>>>>> > It could be that it is relying upon context to determine if >>>>>>> something should be exported (debug flag etc.) >>>>>>> >>>>>>> so if two importers happen at different times the second importer >>>>>>> can compromise with undesired features the first one or vice-verssa? >>>>>>> >>>>>>> Dynamic exports are possible since ever on CommonJS world (same as >>>>>>> imports) and I've truly rarely seen the need to lazy export or lazy >>>>>>> import. >>>>>>> Conditional import yes, and conditional exports too but never at >>>>>>> distance. >>>>>>> >>>>>>> So, like I've said, I don't see real-world scenarios for exported >>>>>>> modules that changes without notice. >>>>>>> It looks unpractical and undesired. >>>>>>> >>>>>>> Can you point at me at a single module that needs to do that? >>>>>>> Maybe I'm missing something. >>>>>>> >>>>>>> Thanks >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> On Fri, Apr 21, 2017 at 7:18 PM, Bradley Meck < >>>>>>> [email protected]> wrote: >>>>>>> >>>>>>>> > Let me ask again: as a module consumer, how are you supposed to >>>>>>>> know when an export is available? >>>>>>>> >>>>>>>> The previous email was stating there are use cases for updating >>>>>>>> exports. >>>>>>>> >>>>>>>> The answer is no pattern has been standardized so it depends on >>>>>>>> your proposed solution. A `then()`-able is already in spec and seems >>>>>>>> like a >>>>>>>> possible choice (though I wouldn't use a Promise); top level await >>>>>>>> could be >>>>>>>> another but blocks the module graph. TDZ poll/checking on imports >>>>>>>> could be >>>>>>>> another (though not-preferable) solution. I am sure we could bikeshed >>>>>>>> other >>>>>>>> approaches. >>>>>>>> >>>>>>>> I don't see "None of these haven't been solved already through >>>>>>>> better pattern." as a response to all the use cases I described. >>>>>>>> >>>>>>>> On Fri, Apr 21, 2017 at 1:13 PM, Andrea Giammarchi < >>>>>>>> [email protected]> wrote: >>>>>>>> >>>>>>>>> None of these haven't been solved already through better pattern. >>>>>>>>> >>>>>>>>> Let me ask again: as a module consumer, how are you supposed to >>>>>>>>> know when an export is available? >>>>>>>>> >>>>>>>>> On Fri, Apr 21, 2017 at 7:08 PM, Bradley Meck < >>>>>>>>> [email protected]> wrote: >>>>>>>>> >>>>>>>>>> Could be several reasons, it could be exporting a counter/log >>>>>>>>>> that changes over time. >>>>>>>>>> >>>>>>>>>> It could be something that is being mocked/spied upon. >>>>>>>>>> >>>>>>>>>> It could be part of a circular dependency and so the modules do >>>>>>>>>> get a hold of eachother without finishing evaluation. >>>>>>>>>> >>>>>>>>>> It could be that it lazily/async populates its exports due to >>>>>>>>>> costs. >>>>>>>>>> >>>>>>>>>> It could be that it is relying upon context to determine if >>>>>>>>>> something should be exported (debug flag etc.) >>>>>>>>>> >>>>>>>>>> Probably plenty more reasons. >>>>>>>>>> >>>>>>>>>> On Fri, Apr 21, 2017 at 11:58 AM, Andrea Giammarchi < >>>>>>>>>> [email protected]> wrote: >>>>>>>>>> >>>>>>>>>>> > a Promise cannot change value over time, unlike a live >>>>>>>>>>> binding. >>>>>>>>>>> >>>>>>>>>>> when is a module that changes values and without any >>>>>>>>>>> notification desirable? >>>>>>>>>>> >>>>>>>>>>> I cannot think about a single use case for wanting that: it's >>>>>>>>>>> not usable from within the module, it won't be usable outside unless >>>>>>>>>>> checked via ... an interval ? >>>>>>>>>>> >>>>>>>>>>> The main point here is that asynchronous import might also >>>>>>>>>>> inevitably mean asynchronous exports. >>>>>>>>>>> >>>>>>>>>>> Early access to unusable modules doesn't seem a real-world >>>>>>>>>>> solution to me. >>>>>>>>>>> >>>>>>>>>>> What am I missing? >>>>>>>>>>> >>>>>>>>>>> Best Regards >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> On Fri, Apr 21, 2017 at 5:48 PM, Bradley Meck < >>>>>>>>>>> [email protected]> wrote: >>>>>>>>>>> >>>>>>>>>>>> I have been thinking about this some, I do think there is >>>>>>>>>>>> something here, but am not sure it warrants any changes. Exporting >>>>>>>>>>>> asynchronously doesn't provide any coordination point so the >>>>>>>>>>>> general idea >>>>>>>>>>>> is to export a Promise, but a Promise cannot change value over >>>>>>>>>>>> time, unlike >>>>>>>>>>>> a live binding. So, a more appropriate way might be to export a >>>>>>>>>>>> "ready" >>>>>>>>>>>> binding that is a Promise. Without some kind of async coordination >>>>>>>>>>>> like a >>>>>>>>>>>> `.then()`-able you would also suffer from `undefined` being a >>>>>>>>>>>> possible >>>>>>>>>>>> initialized and uninitialized value. >>>>>>>>>>>> >>>>>>>>>>>> ``` >>>>>>>>>>>> let later; >>>>>>>>>>>> export {later}; >>>>>>>>>>>> export const ready = someAsyncWork().then(v => later = v); >>>>>>>>>>>> ``` >>>>>>>>>>>> >>>>>>>>>>>> This does still mean that `later` can be accessed before it is >>>>>>>>>>>> ready, in my opinion somewhat against the idea of a TDZ wanting to >>>>>>>>>>>> wait for >>>>>>>>>>>> access to be ready. >>>>>>>>>>>> >>>>>>>>>>>> I would be interested in something like: >>>>>>>>>>>> >>>>>>>>>>>> ``` >>>>>>>>>>>> async let later; >>>>>>>>>>>> export {later}; >>>>>>>>>>>> export const ready = someAsyncWork().then(v => later = v); >>>>>>>>>>>> ``` >>>>>>>>>>>> >>>>>>>>>>>> That preserves the TDZ until assignment. Or, something that >>>>>>>>>>>> wraps `later` in a non-promise `.then()`-able that `import` >>>>>>>>>>>> understands and >>>>>>>>>>>> can unwrap to a live binding. >>>>>>>>>>>> >>>>>>>>>>>> All of that said, I am not sure this specific of a use warrants >>>>>>>>>>>> language changes as I can think of problems with the ideas I have >>>>>>>>>>>> proposed >>>>>>>>>>>> as well. >>>>>>>>>>>> >>>>>>>>>>>> On Fri, Apr 21, 2017 at 11:24 AM, Benoit Marchant < >>>>>>>>>>>> [email protected]> wrote: >>>>>>>>>>>> >>>>>>>>>>>>> I really like that idea >>>>>>>>>>>>> >>>>>>>>>>>>> On Apr 21, 2017, at 08:22, Andrea Giammarchi < >>>>>>>>>>>>> [email protected]> wrote: >>>>>>>>>>>>> >>>>>>>>>>>>> nobody has any thought on this ? >>>>>>>>>>>>> >>>>>>>>>>>>> Maybe the following pattern would be just about enough to >>>>>>>>>>>>> solve a generic asynchronous import/export ? >>>>>>>>>>>>> >>>>>>>>>>>>> ```js >>>>>>>>>>>>> export default new Promise(async $export => { >>>>>>>>>>>>> >>>>>>>>>>>>> const utils = await import('./utils.js').default; >>>>>>>>>>>>> >>>>>>>>>>>>> $export({module: 'asynchronous', utils}); >>>>>>>>>>>>> >>>>>>>>>>>>> }); >>>>>>>>>>>>> ``` >>>>>>>>>>>>> >>>>>>>>>>>>> Best Regards >>>>>>>>>>>>> >>>>>>>>>>>>> On Thu, Apr 20, 2017 at 11:51 AM, Andrea Giammarchi < >>>>>>>>>>>>> [email protected]> wrote: >>>>>>>>>>>>> >>>>>>>>>>>>>> Even if unpolyfillable through simple `function import() {}` >>>>>>>>>>>>>> declaration, >>>>>>>>>>>>>> I've managed to create a polyfill/payground for the ESnext's >>>>>>>>>>>>>> dynamic import() [1] >>>>>>>>>>>>>> >>>>>>>>>>>>>> This also made me wonder if there's any plan to provide a way >>>>>>>>>>>>>> to asynchronously >>>>>>>>>>>>>> export modules that depends on those that use asynchronous >>>>>>>>>>>>>> import. >>>>>>>>>>>>>> >>>>>>>>>>>>>> Since AFAIK modules have no top-level await, the only pattern >>>>>>>>>>>>>> I can see right now >>>>>>>>>>>>>> to import something asynchronous is the following one: >>>>>>>>>>>>>> >>>>>>>>>>>>>> ```js >>>>>>>>>>>>>> // module ./js/c.js >>>>>>>>>>>>>> export default Promise.all([ >>>>>>>>>>>>>> import('./js/a.js'), >>>>>>>>>>>>>> import('./js/a.js') >>>>>>>>>>>>>> ]).then([a, b] => { >>>>>>>>>>>>>> const module = {a, b, c() {}}; >>>>>>>>>>>>>> return module; >>>>>>>>>>>>>> }); >>>>>>>>>>>>>> >>>>>>>>>>>>>> // module that uses ./js/c.js >>>>>>>>>>>>>> import('./js/c.js').then(m => m.default).then(c => { >>>>>>>>>>>>>> c.a(); c.b(); c.c(); >>>>>>>>>>>>>> }); >>>>>>>>>>>>>> ``` >>>>>>>>>>>>>> >>>>>>>>>>>>>> However, above boilerplate doesn't seem ideal compared with >>>>>>>>>>>>>> something like the following: >>>>>>>>>>>>>> >>>>>>>>>>>>>> ```js >>>>>>>>>>>>>> // module ./js/c.js >>>>>>>>>>>>>> export default await Promise.all([ >>>>>>>>>>>>>> import('./js/a.js'), >>>>>>>>>>>>>> import('./js/a.js') >>>>>>>>>>>>>> ]).then([a, b] => { >>>>>>>>>>>>>> const module = {a, b, c() {}}; >>>>>>>>>>>>>> return module; >>>>>>>>>>>>>> }); >>>>>>>>>>>>>> >>>>>>>>>>>>>> // module that uses ./js/c.js >>>>>>>>>>>>>> import * as c from './js/c.js'; >>>>>>>>>>>>>> ``` >>>>>>>>>>>>>> >>>>>>>>>>>>>> But again, AFAIK that's not possible. >>>>>>>>>>>>>> >>>>>>>>>>>>>> The clear advantage is that the module consumer wouldn't need >>>>>>>>>>>>>> to know, or care, >>>>>>>>>>>>>> if the loaded module depends on some dynamic, asynchronous, >>>>>>>>>>>>>> import, >>>>>>>>>>>>>> meaning modules can be updated and eventually moved to async >>>>>>>>>>>>>> transparently >>>>>>>>>>>>>> for any module consumer. >>>>>>>>>>>>>> >>>>>>>>>>>>>> As summary, is any solution worth >>>>>>>>>>>>>> exploring/improving/fixing/planning? >>>>>>>>>>>>>> >>>>>>>>>>>>>> Thank you. >>>>>>>>>>>>>> Best Regards >>>>>>>>>>>>>> >>>>>>>>>>>>>> [1] https://github.com/WebReflection/import.js#importjs >>>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>>> _______________________________________________ >>>>>>>>>>>>> es-discuss mailing list >>>>>>>>>>>>> [email protected] >>>>>>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>>> _______________________________________________ >>>>>>>>>>>>> es-discuss mailing list >>>>>>>>>>>>> [email protected] >>>>>>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>> >>>>>>>>> >>>>>>>> >>>>>>> >>>>>> >>>>> >>>> >>>> _______________________________________________ >>>> es-discuss mailing list >>>> [email protected] >>>> https://mail.mozilla.org/listinfo/es-discuss >>>> >>>> >>>> >>> >>> _______________________________________________ >>> es-discuss mailing list >>> [email protected] >>> https://mail.mozilla.org/listinfo/es-discuss >>> >>> >> >> _______________________________________________ >> es-discuss mailing list >> [email protected] >> https://mail.mozilla.org/listinfo/es-discuss >> >> > > _______________________________________________ > es-discuss mailing list > [email protected] > https://mail.mozilla.org/listinfo/es-discuss > >
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

