dynamic import() polyfill + question
P.S. the double import('./js/a.js')
was a copy-pasta error, it should've
been a
and b
Promise.all([
import('./js/a.js'),
import('./js/b.js')
])
P.S. the double `import('./js/a.js')` was a copy-pasta error, it should've been `a` and `b` ```js Promise.all([ import('./js/a.js'), import('./js/b.js') ]) ``` On Thu, Apr 20, 2017 at 11:51 AM, Andrea Giammarchi < andrea.giammarchi at gmail.com> 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 > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170420/c22ad5f9/attachment.html>
nobody has any thought on this ?
Maybe the following pattern would be just about enough to solve a generic asynchronous import/export ?
export default new Promise(async $export => {
const utils = await import('./utils.js').default;
$export({module: 'asynchronous', utils});
});
Best
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 < andrea.giammarchi at gmail.com> 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 > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170421/84e94329/attachment.html>
I really like that idea
I really like that idea > On Apr 21, 2017, at 08:22, Andrea Giammarchi <andrea.giammarchi at gmail.com> 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 <andrea.giammarchi at gmail.com> 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 > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170421/a08c19c0/attachment.html>
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.
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 <marchant at mac.com> wrote: > I really like that idea > > On Apr 21, 2017, at 08:22, Andrea Giammarchi <andrea.giammarchi at gmail.com> > 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 < > andrea.giammarchi at gmail.com> 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 > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170421/b8a12c30/attachment-0001.html>
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
> 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 <bradley.meck at gmail.com> 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 <marchant at mac.com> > wrote: > >> I really like that idea >> >> On Apr 21, 2017, at 08:22, Andrea Giammarchi <andrea.giammarchi at gmail.com> >> 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 < >> andrea.giammarchi at gmail.com> 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 >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170421/06cd03d6/attachment.html>
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.
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 < andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> > 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 <marchant at mac.com> >> wrote: >> >>> I really like that idea >>> >>> On Apr 21, 2017, at 08:22, Andrea Giammarchi < >>> andrea.giammarchi at gmail.com> 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 < >>> andrea.giammarchi at gmail.com> 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 >>> es-discuss at mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >>> >>> _______________________________________________ >>> es-discuss mailing list >>> es-discuss at mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170421/3e214564/attachment.html>
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?
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 <bradley.meck at gmail.com> 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 < > andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> >> 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 <marchant at mac.com> >>> wrote: >>> >>>> I really like that idea >>>> >>>> On Apr 21, 2017, at 08:22, Andrea Giammarchi < >>>> andrea.giammarchi at gmail.com> 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 < >>>> andrea.giammarchi at gmail.com> 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 >>>> es-discuss at mozilla.org >>>> https://mail.mozilla.org/listinfo/es-discuss >>>> >>>> >>>> _______________________________________________ >>>> es-discuss mailing list >>>> es-discuss at mozilla.org >>>> https://mail.mozilla.org/listinfo/es-discuss >>>> >>>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170421/ef791c4f/attachment-0001.html>
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.
> 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 < andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> > 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 < >> andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> >>> 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 <marchant at mac.com> >>>> wrote: >>>> >>>>> I really like that idea >>>>> >>>>> On Apr 21, 2017, at 08:22, Andrea Giammarchi < >>>>> andrea.giammarchi at gmail.com> 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 < >>>>> andrea.giammarchi at gmail.com> 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/pla >>>>>> nning? >>>>>> >>>>>> Thank you. >>>>>> Best Regards >>>>>> >>>>>> [1] https://github.com/WebReflection/import.js#importjs >>>>>> >>>>> >>>>> _______________________________________________ >>>>> es-discuss mailing list >>>>> es-discuss at mozilla.org >>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>> >>>>> >>>>> _______________________________________________ >>>>> es-discuss mailing list >>>>> es-discuss at mozilla.org >>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>> >>>>> >>>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170421/5ccab259/attachment-0001.html>
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.
> 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 <bradley.meck at gmail.com> 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 < > andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> >> 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 < >>> andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> >>>> 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 <marchant at mac.com> >>>>> wrote: >>>>> >>>>>> I really like that idea >>>>>> >>>>>> On Apr 21, 2017, at 08:22, Andrea Giammarchi < >>>>>> andrea.giammarchi at gmail.com> 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 < >>>>>> andrea.giammarchi at gmail.com> 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/pla >>>>>>> nning? >>>>>>> >>>>>>> Thank you. >>>>>>> Best Regards >>>>>>> >>>>>>> [1] https://github.com/WebReflection/import.js#importjs >>>>>>> >>>>>> >>>>>> _______________________________________________ >>>>>> es-discuss mailing list >>>>>> es-discuss at mozilla.org >>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>> >>>>>> >>>>>> _______________________________________________ >>>>>> es-discuss mailing list >>>>>> es-discuss at mozilla.org >>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>> >>>>>> >>>>> >>>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170421/a141a42c/attachment.html>
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.
> 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 < andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> > 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 < >> andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> >>> 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 < >>>> andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> >>>>> 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 <marchant at mac.com> >>>>>> wrote: >>>>>> >>>>>>> I really like that idea >>>>>>> >>>>>>> On Apr 21, 2017, at 08:22, Andrea Giammarchi < >>>>>>> andrea.giammarchi at gmail.com> 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 < >>>>>>> andrea.giammarchi at gmail.com> 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/pla >>>>>>>> nning? >>>>>>>> >>>>>>>> Thank you. >>>>>>>> Best Regards >>>>>>>> >>>>>>>> [1] https://github.com/WebReflection/import.js#importjs >>>>>>>> >>>>>>> >>>>>>> _______________________________________________ >>>>>>> es-discuss mailing list >>>>>>> es-discuss at mozilla.org >>>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>>> >>>>>>> >>>>>>> _______________________________________________ >>>>>>> es-discuss mailing list >>>>>>> es-discuss at mozilla.org >>>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>>> >>>>>>> >>>>>> >>>>> >>>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170421/55e4a951/attachment-0001.html>
I’ve run into something like this. An object A has the role to augment another’s B capability, but should only do so if someone actually require/import B. Right now A forces B to load, because we haven’t built in our Mr require package (browser+node) the api that would create the promise of a module without causing it to load, but if someone require(B), then that promise would resole and A would be able to add to B.
Hope that clear enough!
Benoit
I’ve run into something like this. An object A has the role to augment another’s B capability, but should only do so if someone actually require/import B. Right now A forces B to load, because we haven’t built in our Mr require package (browser+node) the api that would create the promise of a module without causing it to load, but if someone require(B), then that promise would resole and A would be able to add to B. Hope that clear enough! Benoit > On Apr 21, 2017, at 11:38 AM, Bradley Meck <bradley.meck at gmail.com> 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 <andrea.giammarchi at gmail.com <mailto:andrea.giammarchi at gmail.com>> 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 <bradley.meck at gmail.com <mailto:bradley.meck at gmail.com>> 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 <andrea.giammarchi at gmail.com <mailto:andrea.giammarchi at gmail.com>> 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 <bradley.meck at gmail.com <mailto:bradley.meck at gmail.com>> 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 <andrea.giammarchi at gmail.com <mailto:andrea.giammarchi at gmail.com>> 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 <bradley.meck at gmail.com <mailto:bradley.meck at gmail.com>> 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 <marchant at mac.com <mailto:marchant at mac.com>> wrote: > I really like that idea > > On Apr 21, 2017, at 08:22, Andrea Giammarchi <andrea.giammarchi at gmail.com <mailto:andrea.giammarchi at gmail.com>> 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 <andrea.giammarchi at gmail.com <mailto:andrea.giammarchi at gmail.com>> 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 <https://github.com/WebReflection/import.js#importjs> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org> >> https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss> > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org <mailto:es-discuss at mozilla.org> > https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss> > > > > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170421/8694d3d7/attachment-0001.html>
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
> 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 <bradley.meck at gmail.com> 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 < > andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> >> 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 < >>> andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> >>>> 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 < >>>>> andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com >>>>>> > 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 <marchant at mac.com> >>>>>>> wrote: >>>>>>> >>>>>>>> I really like that idea >>>>>>>> >>>>>>>> On Apr 21, 2017, at 08:22, Andrea Giammarchi < >>>>>>>> andrea.giammarchi at gmail.com> 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 < >>>>>>>> andrea.giammarchi at gmail.com> 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/pla >>>>>>>>> nning? >>>>>>>>> >>>>>>>>> Thank you. >>>>>>>>> Best Regards >>>>>>>>> >>>>>>>>> [1] https://github.com/WebReflection/import.js#importjs >>>>>>>>> >>>>>>>> >>>>>>>> _______________________________________________ >>>>>>>> es-discuss mailing list >>>>>>>> es-discuss at mozilla.org >>>>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>>>> >>>>>>>> >>>>>>>> _______________________________________________ >>>>>>>> es-discuss mailing list >>>>>>>> es-discuss at mozilla.org >>>>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>>>> >>>>>>>> >>>>>>> >>>>>> >>>>> >>>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170421/eeaed0b6/attachment-0001.html>
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);
> 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 < andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> > 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 < >> andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> >>> 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 < >>>> andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> >>>>> 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 < >>>>>> andrea.giammarchi at gmail.com> 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 < >>>>>>> bradley.meck at gmail.com> 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 <marchant at mac.com >>>>>>>> > wrote: >>>>>>>> >>>>>>>>> I really like that idea >>>>>>>>> >>>>>>>>> On Apr 21, 2017, at 08:22, Andrea Giammarchi < >>>>>>>>> andrea.giammarchi at gmail.com> 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 < >>>>>>>>> andrea.giammarchi at gmail.com> 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/pla >>>>>>>>>> nning? >>>>>>>>>> >>>>>>>>>> Thank you. >>>>>>>>>> Best Regards >>>>>>>>>> >>>>>>>>>> [1] https://github.com/WebReflection/import.js#importjs >>>>>>>>>> >>>>>>>>> >>>>>>>>> _______________________________________________ >>>>>>>>> es-discuss mailing list >>>>>>>>> es-discuss at mozilla.org >>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>>>>> >>>>>>>>> >>>>>>>>> _______________________________________________ >>>>>>>>> es-discuss mailing list >>>>>>>>> es-discuss at mozilla.org >>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>>>>> >>>>>>>>> >>>>>>>> >>>>>>> >>>>>> >>>>> >>>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170421/a492f152/attachment-0001.html>
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" <bradley.meck at gmail.com> 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);
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" <bradley.meck at gmail.com> 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 < andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> > 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 < >> andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> >>> 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 < >>>> andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> >>>>> 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 < >>>>>> andrea.giammarchi at gmail.com> 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 < >>>>>>> bradley.meck at gmail.com> 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 <marchant at mac.com >>>>>>>> > wrote: >>>>>>>> >>>>>>>>> I really like that idea >>>>>>>>> >>>>>>>>> On Apr 21, 2017, at 08:22, Andrea Giammarchi < >>>>>>>>> andrea.giammarchi at gmail.com> 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 < >>>>>>>>> andrea.giammarchi at gmail.com> 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/pla >>>>>>>>>> nning? >>>>>>>>>> >>>>>>>>>> Thank you. >>>>>>>>>> Best Regards >>>>>>>>>> >>>>>>>>>> [1] https://github.com/WebReflection/import.js#importjs >>>>>>>>>> >>>>>>>>> >>>>>>>>> _______________________________________________ >>>>>>>>> es-discuss mailing list >>>>>>>>> es-discuss at mozilla.org >>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>>>>> >>>>>>>>> >>>>>>>>> _______________________________________________ >>>>>>>>> es-discuss mailing list >>>>>>>>> es-discuss at mozilla.org >>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>>>>> >>>>>>>>> >>>>>>>> >>>>>>> >>>>>> >>>>> >>>> >>> >> > _______________________________________________ es-discuss mailing list es-discuss at mozilla.org https://mail.mozilla.org/listinfo/es-discuss -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170422/8eb88eb3/attachment-0001.html>
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
import await * as module from './module.js';
> 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 <matthewwrobb at gmail.com> 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" <bradley.meck at gmail.com> 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 < > andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> >> 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 < >>> andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> >>>> 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 < >>>>> andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com >>>>>> > 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 < >>>>>>> andrea.giammarchi at gmail.com> 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 < >>>>>>>> bradley.meck at gmail.com> 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 < >>>>>>>>> marchant at mac.com> wrote: >>>>>>>>> >>>>>>>>>> I really like that idea >>>>>>>>>> >>>>>>>>>> On Apr 21, 2017, at 08:22, Andrea Giammarchi < >>>>>>>>>> andrea.giammarchi at gmail.com> 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 < >>>>>>>>>> andrea.giammarchi at gmail.com> 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/pla >>>>>>>>>>> nning? >>>>>>>>>>> >>>>>>>>>>> Thank you. >>>>>>>>>>> Best Regards >>>>>>>>>>> >>>>>>>>>>> [1] https://github.com/WebReflection/import.js#importjs >>>>>>>>>>> >>>>>>>>>> >>>>>>>>>> _______________________________________________ >>>>>>>>>> es-discuss mailing list >>>>>>>>>> es-discuss at mozilla.org >>>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> _______________________________________________ >>>>>>>>>> es-discuss mailing list >>>>>>>>>> es-discuss at mozilla.org >>>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>>>>>> >>>>>>>>>> >>>>>>>>> >>>>>>>> >>>>>>> >>>>>> >>>>> >>>> >>> >> > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170422/f20ddb8a/attachment-0001.html>
If the discussion is about a polyfill for import() tc39/proposal-dynamic-import (not the static import)
it's not too hard: gist.github.com/caub/458cfe944f8abcf7b1aec608d0a878cc
(async()=>{
const [Stuff, {foo, bar}] = await Promise.all(['./x',
'./y'].map(require));
// ..
})()
2017-04-22 16:31 GMT+02:00 Andrea Giammarchi <andrea.giammarchi at gmail.com>:
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/458cfe944f8abcf7b1aec608d0a878cc ```js (async()=>{ const [Stuff, {foo, bar}] = await Promise.all(['./x', './y'].map(require)); // .. })() ``` 2017-04-22 16:31 GMT+02:00 Andrea Giammarchi <andrea.giammarchi at gmail.com>: > > 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 <matthewwrobb at gmail.com> > 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" <bradley.meck at gmail.com> 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 < >> andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> >>> 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 < >>>> andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> >>>>> 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 < >>>>>> andrea.giammarchi at gmail.com> 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 < >>>>>>> bradley.meck at gmail.com> 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 < >>>>>>>> andrea.giammarchi at gmail.com> 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 < >>>>>>>>> bradley.meck at gmail.com> 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 < >>>>>>>>>> marchant at mac.com> wrote: >>>>>>>>>> >>>>>>>>>>> I really like that idea >>>>>>>>>>> >>>>>>>>>>> On Apr 21, 2017, at 08:22, Andrea Giammarchi < >>>>>>>>>>> andrea.giammarchi at gmail.com> 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 < >>>>>>>>>>> andrea.giammarchi at gmail.com> 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/pla >>>>>>>>>>>> nning? >>>>>>>>>>>> >>>>>>>>>>>> Thank you. >>>>>>>>>>>> Best Regards >>>>>>>>>>>> >>>>>>>>>>>> [1] https://github.com/WebReflection/import.js#importjs >>>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> _______________________________________________ >>>>>>>>>>> es-discuss mailing list >>>>>>>>>>> es-discuss at mozilla.org >>>>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> _______________________________________________ >>>>>>>>>>> es-discuss mailing list >>>>>>>>>>> es-discuss at mozilla.org >>>>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>> >>>>>>>>> >>>>>>>> >>>>>>> >>>>>> >>>>> >>>> >>> >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> >> >> > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170422/f68380b8/attachment-0001.html>
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:
WebReflection/import.js
The universal attempt to add .import()
as CommonJS module is here:
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 ^_^)
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 <cyril.auburtin at gmail.com> 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/ > 458cfe944f8abcf7b1aec608d0a878cc > > ```js > (async()=>{ > const [Stuff, {foo, bar}] = await Promise.all(['./x', > './y'].map(require)); > // .. > })() > > > ``` > > 2017-04-22 16:31 GMT+02:00 Andrea Giammarchi <andrea.giammarchi at gmail.com> > : > >> > 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 <matthewwrobb at gmail.com> >> 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" <bradley.meck at gmail.com> 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 < >>> andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> >>>> 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 < >>>>> andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com >>>>>> > 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 < >>>>>>> andrea.giammarchi at gmail.com> 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 < >>>>>>>> bradley.meck at gmail.com> 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 < >>>>>>>>> andrea.giammarchi at gmail.com> 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 < >>>>>>>>>> bradley.meck at gmail.com> 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 < >>>>>>>>>>> marchant at mac.com> wrote: >>>>>>>>>>> >>>>>>>>>>>> I really like that idea >>>>>>>>>>>> >>>>>>>>>>>> On Apr 21, 2017, at 08:22, Andrea Giammarchi < >>>>>>>>>>>> andrea.giammarchi at gmail.com> 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 < >>>>>>>>>>>> andrea.giammarchi at gmail.com> 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 >>>>>>>>>>>> es-discuss at mozilla.org >>>>>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> _______________________________________________ >>>>>>>>>>>> es-discuss mailing list >>>>>>>>>>>> es-discuss at mozilla.org >>>>>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>> >>>>>>>>> >>>>>>>> >>>>>>> >>>>>> >>>>> >>>> >>> >>> _______________________________________________ >>> es-discuss mailing list >>> es-discuss at mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >>> >>> >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> >> > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170422/77ffc61a/attachment-0001.html>
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.
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" <andrea.giammarchi at gmail.com> 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 <cyril.auburtin at gmail.com> > 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 <andrea.giammarchi at gmail.com >> >: >> >>> > 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 <matthewwrobb at gmail.com> >>> 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" <bradley.meck at gmail.com> 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 < >>>> andrea.giammarchi at gmail.com> 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 <bradley.meck at gmail.com> >>>>> 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 < >>>>>> andrea.giammarchi at gmail.com> 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 < >>>>>>> bradley.meck at gmail.com> 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 < >>>>>>>> andrea.giammarchi at gmail.com> 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 < >>>>>>>>> bradley.meck at gmail.com> 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 < >>>>>>>>>> andrea.giammarchi at gmail.com> 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 < >>>>>>>>>>> bradley.meck at gmail.com> 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 < >>>>>>>>>>>> marchant at mac.com> wrote: >>>>>>>>>>>> >>>>>>>>>>>>> I really like that idea >>>>>>>>>>>>> >>>>>>>>>>>>> On Apr 21, 2017, at 08:22, Andrea Giammarchi < >>>>>>>>>>>>> andrea.giammarchi at gmail.com> 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 < >>>>>>>>>>>>> andrea.giammarchi at gmail.com> 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 >>>>>>>>>>>>> es-discuss at mozilla.org >>>>>>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>>> _______________________________________________ >>>>>>>>>>>>> es-discuss mailing list >>>>>>>>>>>>> es-discuss at mozilla.org >>>>>>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>> >>>>>>>>> >>>>>>>> >>>>>>> >>>>>> >>>>> >>>> >>>> _______________________________________________ >>>> es-discuss mailing list >>>> es-discuss at mozilla.org >>>> https://mail.mozilla.org/listinfo/es-discuss >>>> >>>> >>>> >>> >>> _______________________________________________ >>> es-discuss mailing list >>> es-discuss at mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >>> >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> >> > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170422/1babadb8/attachment-0001.html>
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:
// 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:
// 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
[1] WebReflection/import.js#importjs