Re: File API Feedback

On Tue, Jun 30, 2009 at 7:36 PM, Jonas Sicking<jonas@sicking.cc> wrote:
> On Tue, Jun 30, 2009 at 6:13 PM, Garrett Smith<dhtmlkitchen@gmail.com> wrote:
>> On Tue, Jun 30, 2009 at 4:29 PM, Jonas Sicking<jonas@sicking.cc> wrote:
>>> On Tue, Jun 30, 2009 at 4:22 PM, Garrett Smith<dhtmlkitchen@gmail.com> wrote:
>>>>> With that in mind, do you still think it makes sense to have progress
>>>>> events and all the other events you are proposing?
>>>>
>>>> I've reread my message. The arguments and reasoning given for Events
>>>> seem clear and concise. The argument for Progress Events was
>>>> illustrated with an example and a comparison. What was confusing?
>>>
>>> What is the use case for the API you are proposing?
>>
>> The program wants to attach more than one "success" callback at places
>> in the code. The program wants to attach a "timeout" callback, to
>> handle cases where the read operation is too slow.
>
> But *why* would someone want to attach more than one success callback?
>

Why would someone want to attach more than one "click" handler to
document? It doesn't really matter why, but it is not hard to imagine
situations.

For example, a notification for all success reads of files to notify
the user of "done", but then specific notifications about the current
file read. Not hard to imagine, but, AISB, it is not necessary to
consider all possible contexts. You have snipped and ignored that and
all other questions. Please don't do that.

AISB, "An asynchronous file read is like an asynchronous XHR, in a
way." It can be desirable to want to have more than one callback for
XHR.

<ajax library aside>
Earlier Ajax libraries hard-coded the callback to wrapped "send". Some
still do (YUI 2 "Connection Manager"). I got stuck using that awful
thing years ago, when at Yahoo and did in fact get in a situation
where the program wanted more than one callback to a connection
"object', and mentioned this problem in emails to at least one or two
of their developers. One who is unfamiliar with basics of event
notification, and has no experience using such APIs might not see that
as a mistake. Looks like YUI 3 beta has a design that accommodates
that.

By moving the callbacks an event abstraction, YUI 3 simplified the
internal methods and made the API more flexible and more stable. This
allows the possibility of adding a new event type without changing
existing methods.
</ajax library aside>

FileUpload API has the same design problems as older Ajax libraries,
which have been corrected. It deserves better.

> What do you mean by timeout? That the OS thinks that accessing the
> file takes so long that it aborts and returns a failure? Or that the
> page thinks it takes too long?

What "the OS thinks" ?

The requirement that determines "inordinately long" comes from a
human, or humans. It is realized in code via a timeout mechanism to
cancel the call. This is prevalent in code that must perform
asynchronously e.g. XHR, animations, etc.

MSDN's XHR and XDR documentation[1] has an example of timeout that is
of particular relevance here; XHR is a data request over http,
FileUpload is a data request in the local network. It is a very common
pattern to have a timeout[2]. Even progress events has a timeout event
(shoehorned into "error")[3].

>
> If the former, there is already an error callback which would be
> called on timeout. If the latter, that seems like a decision the page
> makes and so no event would be involved.

FWICT, in the current FileUpload API, error callbacks are not called
on timeout. I have no idea what you mean by "a decision the page
makes".

>
> However having a function that allows you to cancel any pending read,
> for example if the read takes too long or is for some other reason no
> longer relevant, seems like it might be worth perusing.
>

Yes.

> Something like FileData.cancelPendingReads() seems like the simplest solution.
>

Something like that, but I don't like that name. It doesn't feel right.

An |abort| method is not bad, but not for timeout. It is very common
to use the abort() method with a "timeout" in Ajax calls. MSIE 8
created a simpler solution: timeout. No stroke of genius, but a design
that was apparently not obvious to other browsers (and I am starting
to see why).

> Though technically the same effect can already be archived if the
> implementation simply ignores the callback when it arrives. I'm not
> sure it's worth adding this API unless it turns out it's something
> that sites actually needs.
>

You lost me on the premise.  It seems like you're jumping to the
conclusion that it is not worth changing the API design unless a site
requires that. The API is unfinished and unused; "the argument that
sites actually need". It is driven by use-case.  Usage patterns and
extensible design deserve consideration and don't take anything away
from the use-cases.

>>> I agree that what
>>> you are proposing allows for a lot of flexibility, but it also results
>>> in an API that is more complex.
>>
>> Hardly. If no new messages (callbacks) are created, the design
>> separates messaging and behavior.
>>
>> How is this:-
>>
>> file.onsuccess = genericSuccess;
>> file.onerror = genericError;
>> file.read();
>>
>> More complicated than:-
>>
>> file.read(genericSuccess, genericError);
>
> This seems more complicated to me. It's three times as many lines of code.
>

Oh brother. Are we really down to seeing how compact the code is now?
I have not heard of counting LOC as an important consideration
criteria for API design.

I think counting LOC is focusing on the wrong thing. The problem,
AISI, is 1) adding callbacks and 2) performing a read. Those are two
distinctly different things. The DOM Events exists for reasons like
this. It provides an interface for event notification. DOM Events has
problems, granted, but it is the Events API we have for now.

I should rather ask: Why does this API shirk DOM Events in favor of
its own inferior callback mechanism?  The FileErrorCallback is an
interface but it has no distinguishing properties. That wants to be an
event.

> And it gets worse if you want to read the data both as raw data and as
> a data-url. For example in order to process the raw data and send it
> to the server, as well as use the data-url to display a preview using
> an <img>. In that case the code would be more something like:
>
> file.onsuccess = handleDataUrl;
> file.onerror = genericError;
> file.readAsDataURL();
>
> function handleDataUrl() {
>  ...
>  file.onsuccess = handleTextDatal;
>  file.readAsText();
> }
>

Spaghetti code.

The documentation for FileDialog[0] has named the callback parameter
to getAsDataURI as "FileAsText ". From the editor's draft:

| getAsDataURI(in FileAsText callback, [Optional] in FileErrorCallback
errorCallback);

Your example raises a good point. There are two reads, each with
different behavior, but callbacks are a shared behavior. Why not have
a Reader for each behavior?

  var reader = file.textReader;
  reader.success = textReadSuccess;
  reader.read();

  reader = file.uriReader;
  reader.success = uriReadSuccess;
  reader.read();

That makes the individual callbacks a lot simpler. It also provides a
"read" interface that works on any type of Reader. It really makes
more sense when you think about it; a File does not read; a Reader
does.

> This is significantly more complicated than:
>
> file.getAsDataUrl(handleDataUrl, genericError);
> file.getAsText(handleText, genericError);
>

Throwing away the callback avoids that problem but has all the
drawbacks I've mentioned.

Garrett

[0]http://dev.w3.org/2006/webapi/FileUpload/publish/FileAPI.xhtml#File-if
[1]http://msdn.microsoft.com/en-us/library/cc534581(VS.85).aspx#timeout_property
[2]http://ajaxpatterns.org/XMLHttpRequest_Call#Detecting_Errors
[3]http://www.w3.org/TR/progress-events/#Event

Received on Thursday, 2 July 2009 04:02:22 UTC