Bug 16953 - createObjectURL and oneTimeOnly behavior should be defined in terms of stable state
createObjectURL and oneTimeOnly behavior should be defined in terms of stable...
Status: RESOLVED WONTFIX
Product: WebAppsWG
Classification: Unclassified
Component: File API
unspecified
PC All
: P2 normal
: ---
Assigned To: Arun
public-webapps-bugzilla
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2012-05-07 15:47 UTC by Arun
Modified: 2012-10-16 15:19 UTC (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Arun 2012-05-07 15:47:49 UTC
URL.createObjectURL and oneTimeOnly should be defined in terms of HTML5 stable state, or microtask, depending on Bug 16790.
Comment 1 Glenn Maynard 2012-05-07 16:23:51 UTC
With that behavior, the name "oneTimeOnly" no longer fits.  I'd suggest "autoRevoke".
Comment 2 Arun 2012-05-07 19:27:24 UTC
My concern with renaming oneTimeOnly is that MSFT may have an implementation in place.  But Comment 1 makes sense; autoRevoke is a better name.
Comment 3 Glenn Maynard 2012-05-07 19:48:11 UTC
It's pretty different from this, though.  It's possible to write code which works with both, but it's also possible to write code that only works with one or the other...

By the way, we also need a way to feature test this (without jumping hoops).  This is a problem for all dictionary-parameter features, so maybe this needs a more generic solution.
Comment 4 Masatoshi Kimura 2012-05-07 23:16:27 UTC
We can use getter for feature detection. For example:
var hasOneTimeOnly = false, hasAutoRevoke = false;
var o = {};
Object.defineProperty(o, "oneTimeOnly", { get: function(){ hasOneTimeOnly = true; return false; } });
Object.defineProperty(o, "autoRevoke", { get: function(){ hasAutoRevoke = true; return false; } });
URL.createObjectURL(new Blob(), o); // getter will be called if supported
Comment 5 Arun 2012-05-08 17:56:37 UTC
Masatoshi, what you say in Comment 4 will probably work (modulo a tweak or two ;-)) but the goal is to avoid code forks, which should be rights be a thing of yesteryear.
Comment 6 Glenn Maynard 2012-05-11 06:44:48 UTC
(In reply to comment #4)
> We can use getter for feature detection. For example:
> var hasOneTimeOnly = false, hasAutoRevoke = false;
> var o = {};
> Object.defineProperty(o, "oneTimeOnly", { get: function(){ hasOneTimeOnly =
> true; return false; } });
> Object.defineProperty(o, "autoRevoke", { get: function(){ hasAutoRevoke = true;
> return false; } });
> URL.createObjectURL(new Blob(), o); // getter will be called if supported

This requires far more knowledge of how IDL dictionaries work than can be reasonably expected.  Feature detection shouldn't be so complex that everyone needs to use a helper library to do it, especially not for something as common as whether an IDL dictionary contains a property.
Comment 7 Arun 2012-07-11 18:53:06 UTC
OK, I've put in a "prose patch" which is now in the WD.  Review welcome:

http://www.w3.org/TR/2012/WD-FileAPI-20120712/#creating-revoking

Few things of note are:

1. autoRevoke is true by default, since there's much resistance to having developers call revokeObjectURL.  In this model, *unless* developers include the autoRevoke="false" dictionary member syntax with a createObjectURL call, they don't need to call revokeObjectURL.

2. We've coupled autoRevoke behavior with stable state in HTML5.  I believe this addresses *most* use cases, but if that assumption is invalid, please say so.
Comment 8 Glenn Maynard 2012-07-11 23:16:15 UTC
(In reply to comment #7)
> 1. autoRevoke is true by default, since there's much resistance to having
> developers call revokeObjectURL.  In this model, *unless* developers include
> the autoRevoke="false" dictionary member syntax with a createObjectURL call,
> they don't need to call revokeObjectURL.

Isn't it too late to change the default?  createObjectURL has been in the wild for quite a while without this.

You need to await a stable state, not provide one (http://www.whatwg.org/specs/web-apps/current-work/#await-a-stable-state).

You don't need to describe what happens when the dictionary argument is omitted; WebIDL will give you the default.

Here's a simplified algorithm:

1. If this method is called with a Blob argument that is not valid, return null and terminate these steps.
2. Return a unique Blob URI that can be used to dereference the blob argument.
3. If the autoRevoke member of the options argument is false, terminate these steps.
4. Asynchronously await a stable state, allowing the task that invoked this algorithm to continue. 
5. Revoke the Blob URI by calling revokeObjectURL on it and terminate these steps.

"Revoke ..." should probably be simply "Revoke the blob URI *URI*", with "revoke the blob URI" being separated out from the definition of revokeObjectURL, instead of having algorithms call function definitions.
Comment 9 Jonas Sicking 2012-07-12 02:46:01 UTC
I'd be willing to try to change Firefox to use autoRevoke as default behavior.

I strongly suspect that the vast majority of code look like:

function doStuff(...) {
  ...
  url = URL.createObjectURL(myblob);
  img.src = url;
  img.onload = function() { URL.revokeObjectURL(url); };
  ...
}

In which case auto-revoking will work just fine.
Comment 10 Arun 2012-07-12 16:20:30 UTC
(In reply to comment #8)
> (In reply to comment #7)
> > 1. autoRevoke is true by default, since there's much resistance to having
> > developers call revokeObjectURL.  In this model, *unless* developers include
> > the autoRevoke="false" dictionary member syntax with a createObjectURL call,
> > they don't need to call revokeObjectURL.
> 
> Isn't it too late to change the default?  createObjectURL has been in the wild
> for quite a while without this.

Yes, but there's also been enough of an outcry against making the default pattern necessitate a revokeObjectURL call that it seemed best to make the default pattern autoRevoke.  Comment 9 suggests to me that as long as we address the majority use case, the temporary pain of changing an implementation is worth the longer term gain of a better default pattern.

> 
> You need to await a stable state, not provide one
> (http://www.whatwg.org/specs/web-apps/current-work/#await-a-stable-state).

OK.  It seems that "await..." is merely used to flesh out "provide..." and I don't know if we can use "await..." in the imperative "must" sense.  It would seem that HTML5 should bolster this a bit.

The gist of what we want done is:

1. To allow the task that spawned the autoRevoke algorithm to run asynchronously TILL the synchronous portions of that script block are done.

2. Then to revoke the Blob URI.

(1. above seems to take care of the genre of use case mentioned in Comment 9, since assignments based on the Blob URI that's been coined are synchronous).


> 
> You don't need to describe what happens when the dictionary argument is
> omitted; WebIDL will give you the default.

Assuming that our understanding is correct, I think Comment 8 is what I'll put in the spec.
Comment 11 Glenn Maynard 2012-07-12 16:33:38 UTC
(In reply to comment #10)
> > You need to await a stable state, not provide one
> > (http://www.whatwg.org/specs/web-apps/current-work/#await-a-stable-state).
> 
> OK.  It seems that "await..." is merely used to flesh out "provide..." and I
> don't know if we can use "await..." in the imperative "must" sense.  It would
> seem that HTML5 should bolster this a bit.

They're two different pieces.  You "provide a stable state" when you're part of a synchronous algorithm and you want things awaiting a stable state to execute.  (You don't want this; this is what things like the event loop and the parser do to trigger it.)  You "await a stable state" to wait for that to happen.

See http://www.whatwg.org/specs/web-apps/current-work/#update-the-image-data for an example of how this is used (which is what I based the text on).

> The gist of what we want done is:
> 
> 1. To allow the task that spawned the autoRevoke algorithm to run
> asynchronously TILL the synchronous portions of that script block are done.
> 
> 2. Then to revoke the Blob URI.

This doesn't sound quite right.  What this is doing, conceptually, is queueing some code (step 5) that will run the next time another algorithm says "provide a stable state", then returning to the caller and continuing as normal.  The task that spawned autoRevoke (namely, the user code calling createObjectURL) doesn't run asynchronously; it simply continues synchronously as usual.

The only thing that's actually happening asynchronously is the "sit around and wait for a stable state to show up" step (4).  Once that happens, the last step (revoking the URL) happens synchronously, before the "provide a stable state" algorithm (invoked externally) returns.

(Just making sure we're on the same page--we're probably just thinking of the same thing in different terms.)

> (1. above seems to take care of the genre of use case mentioned in Comment 9,
> since assignments based on the Blob URI that's been coined are synchronous).

This will definitely work for that sort of thing, at least once the "take a reference on src assignment" stuff is done.  (We've talked about that before but it needs to be fleshed out and specced.  I'll file a separate bug for that later today.)

> Assuming that our understanding is correct, I think Comment 8 is what I'll put
> in the spec.

One thing I missed: step 5 (release the URL) needs to happen in a synchronous section, to guarantee it completes before "provide a stable state" returns.  See  update-the-image-data; I think we can just append "The synchronous section consists of all the remaining steps of this algorithm." to step 4.
Comment 12 Arun 2012-10-16 15:19:31 UTC
See Bug 19554.