dynamic import() polyfill + question

Bradley Meck bradley.meck at gmail.com
Fri Apr 21 19:10:08 UTC 2017


> 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>


More information about the es-discuss mailing list