Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-15 Thread Jake Archibald
Thanks, updated my code examples to reflect this


On 14 March 2014 23:57, Boris Zbarsky bzbar...@mit.edu wrote:

 On 3/14/14 6:04 PM, Jake Archibald wrote:

 Any guarantees of ordering if fully cached?


 I believe no.

 -Boris



Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-15 Thread Jake Archibald
On 15 March 2014 00:31, Kyle Simpson get...@gmail.com wrote:

 I'd say the first syntax is a bit verbose for what I was dreaming 4 years
 ago when I started asking for a simple script preloading mechanism, but
 it's just this side of acceptable. If we have to take the second approach,
 I say that's unacceptably more verbose/complex and falls short of my
 opinion of everything we need for sane  versitile dependency loading.


It's everything we need but perhaps not everything we desire. Last time we
went round with script loading the proposal for high-level dependency
declaration got weighed down by use-cases that should have been left to
lower level primitives. These are the lower level bits, something higher
level is still possible. For legacy-free project, modules + promises for
non-script assets are the answer.

I updated my examples to deal with no guarantees of script order. A couple
of forEachs were turned to reduces, that was it.


Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-15 Thread Jake Archibald
On 15 March 2014 00:35, Kyle Simpson get...@gmail.com wrote:

 there's a seemingly implicit requirement that we have to get both ES6
 promises and DOM promises to land for these suggested approaches to work.


ES6 promises are already in Chrome stable, they're on the route to stable
in Firefox. Promises will only be absent in browsers that have no intention
of being ES6 compliant.


 At one point the conversation shifted towards ServiceWorker as being the
 answer.


It isn't. Network requests are still async in a ServiceWorker world. You
can use it to prepare caches and respond to requests with it, but if your
response strategy is try cache, then network, then fallback link
rel=preload can still give you a performance benefit by going through that
process sooner.


 Why isn't putting preloading into existing script elements (whether
 exposed by events or by promises) better than splitting it out into a
 separate element (link rel=preload) and requiring a third mechanism
 (promises) to wire them up?


Preloading is important for more than just scripts, making it a script-only
feature is restrictive. Preloading is useful for images, audio sprites,
initial JSON requests etc etc.

Is there any chance we could take a fresh look at the earlier proposals
 (putting both preloading and loading/exec into script), and perhaps
 freshen them up with promises instead of events?


Going back to the proposal in the OP, this isn't intended as the full
solution to the previous script loading thread(s). All new async/failure JS
 DOM APIs use promises, but our existing APIs need this love too. Not just
for scripts, but for stylesheets, images, xhr and mixing all those things
together with Promise.all.

link rel=preload is a separate effort, but I wanted to show the
flexibility you get with these components and add to the use-cases.

Yes, the script loading stuff can be revisited, but it's a separate effort
to these promise-vending methods  link rel=preload.


Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-15 Thread Kyle Simpson
 As I noted above, what we need to know (and I guess we need to know this 
 from all browsers) if there's a *guarantee* of a-b-c execution order (even 
 if all 3 are executing async)
 
 I don't believe there is such a guarantee, unless the spec spells it out 
 explicitly.


The `async=false` stuff in the spec talks about dynamically loaded (not parser 
loaded) scripts going into a queue so they are downloaded in parallel, but 
executed in request-order from the queue.

So, in my aforementioned `execScript(..)` function, if it also set `s.async = 
false`, I believe that would opt all of the scripts into the async queue.

function execScript(l) {
  var s = document.createElement(script);
  s.async = false; // -- insert this to get ordered-async
  s.src = l.href;
  document.head.appendChild(s);
  return s.loaded();
}

Even though all of them would, at that point, be strictly loading from cache, 
it should still have the effect of ensuring they execute strictly in a-b-c 
order, correct?



-


One downside to this is that there were use-cases where the single queue that 
this spec mechanism created were not sufficient, such as loading a group of 
scripts for widget A and another independent group of scripts widget B, and not 
wanting A or B to block the other.

If all of those scripts were set with `async=false` and thus all put in that 
single queue, widget A's scripts could block widget B's scripts, which sorta 
fails that use-case.

However, it would probably only be a slight delay, as you wouldn't (in the 
previously mentioned code pattern) add the script elements to the DOM (and 
thus the queue) until after all the link rel=preload's had finished loading, 
so it would only be parsing/execution that blocked, not downloading.

Execution is already an implicit blocking, as the engine can only run one 
script at a time, so actually, it's just a concern of potential parsing 
blocking other parsing.

The question is whether `async=false` scripts in the queue can be parsed in 
parallel (unblocked from each other) on the background threads, as you said, or 
whether being in that async=false queue means that both parsing and execution 
happen in order, and thus could cause long parsing of widget A's scripts from 
blocking parsing of widget B's scripts?

However you slice it, I think it would cause *some* delays between widget A and 
B (aka, not totally independent), but it would in general be far less delays 
than what we have currently, which is that downloading blocks in that queue. So 
that seems like a big (if not complete) win. :)



--Kyle








Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-15 Thread Kyle Simpson
 I'd say the first syntax is a bit verbose for what I was dreaming 4 years
 ago when I started asking for a simple script preloading mechanism, but
 it's just this side of acceptable. If we have to take the second approach,
 I say that's unacceptably more verbose/complex and falls short of my
 opinion of everything we need for sane  versitile dependency loading.
 
 It's everything we need but perhaps not everything we desire.


If everything we need was the only standard, then the proposals we had 
discussed years ago should have been pushed through, years ago. Those 
discussions were bogged down because, as you say in the next sentence (quoted 
below), there were some on this list who insisted that mechanisms which 
couldn't be markup-only were insufficient, not just undesirable.

For my part, I hope our current discussion thread is signaling a shift from the 
previous dogmatism (on all sides).



 Last time we
 went round with script loading the proposal for high-level dependency
 declaration got weighed down by use-cases that should have been left to
 lower level primitives. These are the lower level bits, something higher
 level is still possible. For legacy-free project, modules + promises for
 non-script assets are the answer.

It was never a priority of *mine* to support zero-script-loader capability. I 
think, and always have, that script loaders are the place where logic for 
anything beyond straight-forward loading *should* occur.

But there was clearly a LOT of noise in the past whenever I pointed out 
advanced use-cases, and this noise led to suggestions about markup-only 
(zero-script-loader) mechanisms for handling all or most of the use-cases in a 
way that theoretically could eliminate any need for script loaders. Recall all 
the discussions of `depends='...'` attributes being able to annotate one 
script's dependencies on another script or scripts?

I was only trying to call out the fact that there had been a very clear 
intention in the past to get some silver-bullet solution that implies 
zero-script-loader, and what we're currently discussing (.loaded() promises) is 
NOT that.

If we are, at this point in the years-long arc of discussion, ready to set that 
requirement aside, and admit that markup capabilities (link rel=preload and 
script) are for the straight linear a-b-c use-cases, and that the more 
sophisticated use-cases (like dynamic loading, independent widgets, etc etc) 
require logic that belongs in some form of script loader (whether a lib or a 
set of inline boilerplate code) that handles all the promises-negotiation, then 
I'm fine with that approach. I say fine relatively, because I don't really 
like the ugliness if we have to ensure order ourselves (maybe we don't!?), but 
it's not a deal-breaker either way.



--Kyle






Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-15 Thread Boris Zbarsky

On 3/15/14 11:36 AM, Kyle Simpson wrote:

The `async=false` stuff in the spec talks about dynamically loaded (not parser 
loaded) scripts going into a queue so they are downloaded in parallel, but 
executed in request-order from the queue.


Then those are guaranteed to be serialized.


The question is whether `async=false` scripts in the queue can be parsed in 
parallel


Nothing prevents that, as long as make sure you don't execute them as 
soon as the parse is done if the previous scripts haven't executed yet.


-Boris


Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-14 Thread Jake Archibald
This, along with Ilya's proposed link rel=preload (
https://docs.google.com/a/google.com/document/d/1HeTVglnZHD_mGSaID1gUZPqLAa1lXWObV-Zkx6q_HF4/edit#heading=h.x6lyw2ttub69),
and JavaScript modules (
https://github.com/dherman/web-modules/blob/master/module-tag/explainer.md)
gives us everything we need for sane  versitile dependency loading.

Problem: Initialising an app on document ready, but also waiting for a
particular stylesheet to apply
Solution: https://gist.github.com/jakearchibald/955e4f014a264b1f50c4

Problem: Initialising an app after a non-module script
Solution: https://gist.github.com/jakearchibald/000ab94ad9fa5cfe62a8

Taking the more complex use-cases from
http://lists.w3.org/Archives/Public/public-whatwg-archive/2013Aug/0277.html…

[Use-case Q:] Want to avoid executing a social-media script until the user
give some intent, although the script should be preloaded.
Solution: https://gist.github.com/jakearchibald/dd25f0f2cf47bf2ab93e

[Use-case S:] One plugin wants to execute A.js and B.js in order
following an interaction. Another wants to load A.js then C.js  D.js
in either order. A.js should only execute once. Scripts aren't written as
modules and out of developer's control.
Solution: https://gist.github.com/jakearchibald/120309d88a8bf025e92e

[Use-case T:] Preload 2 scripts, execute one or the other on particular
interactions
Solution: Same as Q.

[Use-case U:] A.js, B.js, C.js - load them in parallel, execute in
order, only execute when all have preloaded.
Solution: https://gist.github.com/jakearchibald/5898e3a4fce62579d75b

[Use-case V:] As U, but don't need to wait for all before executing. Stop
executing if any script fails to load.
Solution: https://gist.github.com/jakearchibald/ea7583d50bf3b46395e0

[Use-case W:] As W, but break on execution errors
Solution: https://gist.github.com/jakearchibald/1b12a0e5414a69d9350f

[Use-case X:] Loading non-js dependencies
Solution: Use XHR + preload for prescanner

[Use-case Y:] Some libraries may need async initialization.
Solution: These libs should provide a ready promise.

[Use-case Z:] Wait on existence of particular element before executing
script
Solution: Either put the script that handles script loading after the
element in question, or use mutation observers

Cheers,
Jake.


On 12 March 2014 14:27, Jake Archibald jaffathec...@gmail.com wrote:

 On 12 March 2014 14:17, Domenic Denicola dome...@domenicdenicola.comwrote:

 var img = document.createElement(img);
 var promise1 = img.loaded();
 img.src = foo.png;
 var promise2 = img.loaded();

 // (1) will promise1 be immediately fulfilled, since img has
 about:blank or similar loaded already?
 // (2) or will promise1 and promise2 fulfill at the same time, since
 promise1 waits until a src appears?
 // (3) or will promise1 be rejected with AbortError, similar to Jake's
 previous case?
 // (4) or it could be rejected with an InvalidStateError saying you
 can't wait for the loading of a non-src'ed image.

 Here (1), (3), and (4) seem to encourage a consistent model of always
 ask for loaded() promises after setting src, otherwise it won't work. It's
 (2) that's problematic as if that's the case then asking for loaded()
 promises before setting src sometimes works, but usually doesn't.


 This is a very good point, and I'd say (4).

 Lets say you didn't change the src:

 (1) Means the promise would reject with an EncodingError as it isn't a
 valid image format
 (2) Would remain unresolved
 (3) N/A
 (4) Reject with InvalidStateError

 The consistency makes me like (4) the most.



Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-14 Thread Kyle Simpson
 This, along with Ilya's proposed link rel=preload (
 https://docs.google.com/a/google.com/document/d/1HeTVglnZHD_mGSaID1gUZPqLAa1lXWObV-Zkx6q_HF4/edit#heading=h.x6lyw2ttub69),
 and JavaScript modules (
 https://github.com/dherman/web-modules/blob/master/module-tag/explainer.md)
 gives us everything we need for sane  versitile dependency loading.


Is link rel=preload going to fire this loaded event after it finishes 
pre-loading but BEFORE it executes (or, rather, BEFORE because it doesn't 
execute them at all)? Because for script, the load event fires only after 
it has loaded AND executed, which is of course too late for many of the more 
advanced use-cases below.

If you want to dynamically *preload* scripts (that is, you don't have link 
rel=preload tags in your initial page markup) later on in the lifetime of the 
page, is the story basically like this?



function preloadScript(src) {
   var l = document.createElement(link);
   l.rel = preload;
   l.href = src;
   document.head.appendChild(l);
   return l.loaded();
}

function execScript(l) {
   var s = document.createElement(script);
   s.src = l.href;
   document.head.appendChild(s);
   return s.loaded();
}

Promise.all(
   preloadScript(a.js),
   preloadScript(b.js),
   preloadScript(c.js)
)
.then(function(links){
   return Promise.all.apply(null,links.map(execScript));
})
.then(function(){
   alert(All scripts loaded and executed);
});
   


So, if that's how we think this would work, we need to understand how the 
`execScript(..)` logic is going to be treated. Is creating a script element 
dynamically and inserting it going to make sure that it either:

  a. executes sync
  b. executes async, but a.js will *definitely* execute before b.js, which 
will *definitely* execute before c.js.

In other words, is there any possibility that it won't execute in order a - 
b - c in the above code? If so, do/don't we have to be more complex, like?



Promise.all(
   preloadScript(a.js),
   preloadScript(b.js),
   preloadScript(c.js)
)
.then(function(links){
   var chain;
   links = links.forEach(function(link){
  if (!chain) chain = execScript(link);
  else chain = chain.then(function(){ return execScript(link); });
   });
   return chain;
})
.then(function(){
   alert(All scripts loaded and executed);
});




--Kyle






Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-14 Thread Jake Archibald
On 14 March 2014 20:10, Kyle Simpson get...@gmail.com wrote:

 Is link rel=preload going to fire this loaded event after it finishes
 pre-loading but BEFORE it executes (or, rather, BEFORE because it doesn't
 execute them at all)?


link rel=preload doesn't execute (you can use it to preload anything), so
loaded() fulfills before execution. With script loaded() fulfills after
execution.


 If you want to dynamically *preload* scripts (that is, you don't have
 link rel=preload tags in your initial page markup) later on in the
 lifetime of the page, is the story basically like this?

 Promise.all(
preloadScript(a.js),
preloadScript(b.js),
preloadScript(c.js)
 )
 .then(function(links){
return Promise.all.apply(null,links.map(execScript));
 })
 .then(function(){
alert(All scripts loaded and executed);
 });

 So, if that's how we think this would work, we need to understand how the
 `execScript(..)` logic is going to be treated. Is creating a script
 element dynamically and inserting it going to make sure that it either:

   a. executes sync
   b. executes async, but a.js will *definitely* execute before b.js,
 which will *definitely* execute before c.js.


I'm hoping a, but you tell me. Do you know what browsers do with a fully
cached script? Is there consistency there? If not, yeah, you'll have to
create a chain.

(btw, Promise.all takes an array, which nicely avoids the .apply stuff)

Jake.


Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-14 Thread Boris Zbarsky

On 3/14/14 5:03 PM, Jake Archibald wrote:

Do you know what browsers do with a fully cached script?


script src=url is always executed async when inserted into the DOM, 
cached or not.


scripttext/script is executed sync.

-Boris


Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-14 Thread Jake Archibald
On 14 March 2014 21:05, Boris Zbarsky bzbar...@mit.edu wrote:

 On 3/14/14 5:03 PM, Jake Archibald wrote:

 Do you know what browsers do with a fully cached script?


 script src=url is always executed async when inserted into the DOM,
 cached or not.


Any guarantees of ordering if fully cached?

If not, yeah, async=false or chain via .loaded is the way to go.


Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-14 Thread Boris Zbarsky

On 3/14/14 6:04 PM, Jake Archibald wrote:

Any guarantees of ordering if fully cached?


I believe no.

-Boris


Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-14 Thread Kyle Simpson
 So, if that's how we think this would work, we need to understand how the
 `execScript(..)` logic is going to be treated. Is creating a script
 element dynamically and inserting it going to make sure that it either:
 
  a. executes sync
  b. executes async, but a.js will *definitely* execute before b.js,
 which will *definitely* execute before c.js.
 
 
 I'm hoping a, but you tell me. Do you know what browsers do with a fully
 cached script? Is there consistency there? If not, yeah, you'll have to
 create a chain.

Regardless of (a) or (b), the simpler Promise approach (my first snippet) is 
sufficient, if and only if a-b-c is the  *guaranteed* execution order. That's 
the important part. If there's a chance the browser might do b-a-c (even if 
all were equally ready in the cache), then the pattern goes fubar and the 
uglier second syntax is required.

I'd say the first syntax is a bit verbose for what I was dreaming 4 years ago 
when I started asking for a simple script preloading mechanism, but it's just 
this side of acceptable. If we have to take the second approach, I say that's 
unacceptably more verbose/complex and falls short of my opinion of everything 
we need for sane  versitile dependency loading.



 Do you know what browsers do with a fully cached script?
 
 script src=url is always executed async when inserted into the DOM, 
 cached or not.

Boris-

As I noted above, what we need to know (and I guess we need to know this from 
all browsers) if there's a *guarantee* of a-b-c execution order (even if all 
3 are executing async) when they are added to the DOM in that order and all 3 
are guaranteed preloaded first, by the link rel=preload tag usage? Is there 
ever a case where some other execution order than a-b-c would happen?




--Kyle







Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-14 Thread Kyle Simpson
I'd also like to make the observation that putting link rel=preload.loaded() 
together with script.loaded(), and indeed needing a promise mechanism to wire 
it altogether, is a fair bit more complicated than the initial proposals for 
script preloading use-cases from the earlier threads over the last few years of 
this list.

For one, we're talking about twice as many DOM elements. For another, there's a 
seemingly implicit requirement that we have to get both ES6 promises and DOM 
promises to land for these suggested approaches to work. I don't know if that's 
already a guarantee or if there are some browsers which are possibly going to 
land DOM promises before ES6 promises? If so, ES6 promises become the long 
pole, which isn't ideal.

Lastly, I'd observe that many of the arguments against the original/previous 
script preloading proposals were heavily weighted towards we don't like script 
loaders, we want to make them obsolete, we need simple enough (declarative 
markup) mechanisms for that stuff so as to make script loaders pointless…

At one point the conversation shifted towards ServiceWorker as being the 
answer. When we explored the use cases, it was my impression there was still a 
fair amount of non-trivial code logic to perform these different loading cases 
with SW, which means for the general user to take advantage of such use-cases, 
they're almost certainly going to need some library to do it.

I can't imagine most end-users writing the previously-suggested ServiceWorker 
code, and I'm having a hard time believing that they'd alternatively be writing 
this newly suggested promises-based loading logic all over their pages. In 
either case, I think for many of the use-cases to be handled, most general 
users will need to use some script-loader lib.

So, if this .loaded() DOM promises thing isn't the silver bullet that gets us 
to no script loader utopia, then I don't see why it's demonstrably better 
than the simpler earlier proposals.

Moreover, the earlier proposals relied on the browser having logic built-in to 
handle stuff like download in parallel, execute serially, which made their 
interface (the surface area users needed to work with) much less than either 
the Promises here or the ServiceWorker before.

What you're implicitly suggesting with both sets of suggestions is, let's make 
the user do the more complicated logic to wire things together, instead of the 
browser doing it. Why?

Why isn't putting preloading into existing script elements (whether exposed 
by events or by promises) better than splitting it out into a separate element 
(link rel=preload) and requiring a third mechanism (promises) to wire them up?



Is there any chance we could take a fresh look at the earlier proposals 
(putting both preloading and loading/exec into script), and perhaps freshen 
them up with promises instead of events?




--Kyle













Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-14 Thread Domenic Denicola
There is no such thing as DOM promises.

From: Kyle Simpsonmailto:get...@gmail.com
Sent: ‎3/‎14/‎2014 20:35
To: whatwg@lists.whatwg.orgmailto:whatwg@lists.whatwg.org
Subject: Re: [whatwg] Promise-vending loaded()  ready() methods on various 
elements

I'd also like to make the observation that putting link rel=preload.loaded() 
together with script.loaded(), and indeed needing a promise mechanism to wire 
it altogether, is a fair bit more complicated than the initial proposals for 
script preloading use-cases from the earlier threads over the last few years of 
this list.

For one, we're talking about twice as many DOM elements. For another, there's a 
seemingly implicit requirement that we have to get both ES6 promises and DOM 
promises to land for these suggested approaches to work. I don't know if that's 
already a guarantee or if there are some browsers which are possibly going to 
land DOM promises before ES6 promises? If so, ES6 promises become the long 
pole, which isn't ideal.

Lastly, I'd observe that many of the arguments against the original/previous 
script preloading proposals were heavily weighted towards we don't like script 
loaders, we want to make them obsolete, we need simple enough (declarative 
markup) mechanisms for that stuff so as to make script loaders pointless…

At one point the conversation shifted towards ServiceWorker as being the 
answer. When we explored the use cases, it was my impression there was still a 
fair amount of non-trivial code logic to perform these different loading cases 
with SW, which means for the general user to take advantage of such use-cases, 
they're almost certainly going to need some library to do it.

I can't imagine most end-users writing the previously-suggested ServiceWorker 
code, and I'm having a hard time believing that they'd alternatively be writing 
this newly suggested promises-based loading logic all over their pages. In 
either case, I think for many of the use-cases to be handled, most general 
users will need to use some script-loader lib.

So, if this .loaded() DOM promises thing isn't the silver bullet that gets us 
to no script loader utopia, then I don't see why it's demonstrably better 
than the simpler earlier proposals.

Moreover, the earlier proposals relied on the browser having logic built-in to 
handle stuff like download in parallel, execute serially, which made their 
interface (the surface area users needed to work with) much less than either 
the Promises here or the ServiceWorker before.

What you're implicitly suggesting with both sets of suggestions is, let's make 
the user do the more complicated logic to wire things together, instead of the 
browser doing it. Why?

Why isn't putting preloading into existing script elements (whether exposed 
by events or by promises) better than splitting it out into a separate element 
(link rel=preload) and requiring a third mechanism (promises) to wire them up?



Is there any chance we could take a fresh look at the earlier proposals 
(putting both preloading and loading/exec into script), and perhaps freshen 
them up with promises instead of events?




--Kyle













Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-14 Thread Boris Zbarsky

On 3/14/14 8:31 PM, Kyle Simpson wrote:

As I noted above, what we need to know (and I guess we need to know this from all 
browsers) if there's a *guarantee* of a-b-c execution order (even if all 3 
are executing async)


I don't believe there is such a guarantee, unless the spec spells it out 
explicitly.


For async scripts, Gecko, does the initial script parse+compile on a 
random background thread from a threadpool, and if there is not an 
explicit dependency between the scripts (which I _think_ is only there 
for parser-inserted scripts) then the script will simply run whenever 
that script's background parse thread finishes.


-Boris


Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-12 Thread Boris Zbarsky

On 3/12/14 7:23 AM, Jake Archibald wrote:

== img/link/script/document/iframe .loaded() ==

If the element hasn't loaded or is loading, vend a promise that
resolves/rejects on its load/error event.
If the element has fired load/error and isn't loading due to a source
change, vend a resolved/rejected promise.


This seems fundamentally racy, no?  In particular, the fact that a new 
load can start (and maybe finish?) between the loaded() call and the 
time when the promise notifies its consumers is a bit worrying.


I agree that we need something better than the current easy-to-miss load 
event setup here, though


-Boris


Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-12 Thread Jake Archibald
On 12 March 2014 13:15, Boris Zbarsky bzbar...@mit.edu wrote:

 On 3/12/14 7:23 AM, Jake Archibald wrote:

 == img/link/script/document/iframe .loaded() ==

 If the element hasn't loaded or is loading, vend a promise that
 resolves/rejects on its load/error event.
 If the element has fired load/error and isn't loading due to a source
 change, vend a resolved/rejected promise.


 This seems fundamentally racy, no?  In particular, the fact that a new
 load can start (and maybe finish?) between the loaded() call and the time
 when the promise notifies its consumers is a bit worrying.


You're right, I was short on detail for that case.

img.src = foo;
var promise1 = img.loaded();
img.src = bar;

I expect promise1 to reject with an AbortError.


Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-12 Thread Boris Zbarsky

On 3/12/14 9:32 AM, Jake Archibald wrote:

You're right, I was short on detail for that case.

img.src = foo;
var promise1 = img.loaded();
img.src = bar;

I expect promise1 to reject with an AbortError.


No, the case I'm worried about is when the first load has already 
finished, you call loaded(), get a promise (already resolved), and then 
a new load starts, and maybe finishes, before the promise has notified 
things.  So more like this:


  var promise1;
  img.onload = function() {
promise1 = img.loaded();
img.onload = null;
img.src = bar;
  };
  img.src = foo;

I realize no one would write actual code like this; the real-life use 
case I'm worried about would be more like this:


  // img is already loaded sometimes
  // Would like to observe a new load
  var promise1 = img.loaded(); // oops! This will be pre-resolved if
   // we were already loaded, but otherwise
   // will resolve with the new load we're
   // about to start.
  img.src = bar;

Is my concern making sense?

Images are particularly pernicious here because img.src = bar might 
synchronously finish the load, even if it fires the load event async.


-Boris


Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-12 Thread Domenic Denicola
From: whatwg-boun...@lists.whatwg.org [mailto:whatwg-boun...@lists.whatwg.org] 
On Behalf Of Boris Zbarsky

   // img is already loaded sometimes
   // Would like to observe a new load
   var promise1 = img.loaded(); // oops! This will be pre-resolved if
// we were already loaded, but otherwise
// will resolve with the new load we're
// about to start.
   img.src = bar;

 Is my concern making sense?

It's interesting, because this is exactly the *wrong* type of code to write 
with promises; whereas it's the *right* type of code for events.

With promises you should only ask for the loaded promise *after* setting 
`src`; anything you retrieve before that represents a previous load. Except, I 
suppose, for the base-case of images with no src, transitioning to having an 
src? Or are they considered to have e.g. loaded `about:blank` already? I.e. 
what should this do?

var img = document.createElement(img);
var promise1 = img.loaded();
img.src = foo.png;
var promise2 = img.loaded();

// (1) will promise1 be immediately fulfilled, since img has about:blank or 
similar loaded already?
// (2) or will promise1 and promise2 fulfill at the same time, since promise1 
waits until a src appears?
// (3) or will promise1 be rejected with AbortError, similar to Jake's previous 
case?
// (4) or it could be rejected with an InvalidStateError saying you can't 
wait for the loading of a non-src'ed image.

Here (1), (3), and (4) seem to encourage a consistent model of always ask for 
loaded() promises after setting src, otherwise it won't work. It's (2) that's 
problematic as if that's the case then asking for loaded() promises before 
setting src sometimes works, but usually doesn't.



Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-12 Thread Boris Zbarsky

On 3/12/14 10:17 AM, Domenic Denicola wrote:

With promises you should only ask for the loaded promise *after* setting `src`


Ah, fair.

I'd been hoping we could get away without having to very carefully order 
the code, but I'm just not seeing a way to do that.



Except, I suppose, for the base-case of images with no src, transitioning to 
having an src? Or are they considered to have e.g. loaded `about:blank` already?


They're not right now.


// (2) or will promise1 and promise2 fulfill at the same time, since promise1 
waits until a src appears?


This is what will happen in current implementations if nothing special 
is done.



// (4) or it could be rejected with an InvalidStateError saying you can't 
wait for the loading of a non-src'ed image.


This would make some sense, yes.

-Boris


Re: [whatwg] Promise-vending loaded() ready() methods on various elements

2014-03-12 Thread Jake Archibald
On 12 March 2014 14:17, Domenic Denicola dome...@domenicdenicola.comwrote:

 var img = document.createElement(img);
 var promise1 = img.loaded();
 img.src = foo.png;
 var promise2 = img.loaded();

 // (1) will promise1 be immediately fulfilled, since img has about:blank
 or similar loaded already?
 // (2) or will promise1 and promise2 fulfill at the same time, since
 promise1 waits until a src appears?
 // (3) or will promise1 be rejected with AbortError, similar to Jake's
 previous case?
 // (4) or it could be rejected with an InvalidStateError saying you
 can't wait for the loading of a non-src'ed image.

 Here (1), (3), and (4) seem to encourage a consistent model of always ask
 for loaded() promises after setting src, otherwise it won't work. It's (2)
 that's problematic as if that's the case then asking for loaded() promises
 before setting src sometimes works, but usually doesn't.


This is a very good point, and I'd say (4).

Lets say you didn't change the src:

(1) Means the promise would reject with an EncodingError as it isn't a
valid image format
(2) Would remain unresolved
(3) N/A
(4) Reject with InvalidStateError

The consistency makes me like (4) the most.