W3C home > Mailing lists > Public > public-webapi@w3.org > February 2007

Re: Progress Use Cases (was Re: Progress event spec)

From: Charles McCathieNevile <chaals@opera.com>
Date: Tue, 06 Feb 2007 11:49:02 +0530
To: "Maciej Stachowiak" <mjs@apple.com>
Cc: "Web API public" <public-webapi@w3.org>
Message-ID: <op.tnbc50c2wxe0ny@widsith.local>

The progress and uploadprogress events are optional events that can be fired by 
(for an example) a user agent in the middle of an XmlHttpRequest (XHR) 
transaction. The start and end of that transaction (whether successfully or in 
some error condition) are, in this example, predefined parts of XHR.

In terms of Media Access Events, it corresponds to the DataReceptionProgress 
event. 

It may never fire. If you want to be compatible with the web, you can trap the 
start and end of an existing load. Since you have no progress information and 
don't know how long it will take, set up an indeterminate activity indicator 
like a spinning wheel or barber pole. If a progress event fires, and provides 
information you can use to determine more accurately the progress, then you can 
change the state of your indicator to reflect the new information (as you would 
anyway, no?). If you never get one, you can silently vanish, flash your bar full 
first, put a statement that you got an object of foo size (which you determine 
by measuring it) or whatever else makes you happy.

If it is necessary to disambiguate the case where the size of the transfer is 
unknown, but has "begun" although no data has been received, from the case where 
there is zero data to be transferred and the transfer has begun, but not yet 
completed then requiring that a progress event MUST not fire for a zero-length 
transfer makes sense. I have no strong opinion on that. Following my assertion 
that you have the load starting, you set up an indeterminate indicator, it 
finishes, and if you like you flash full and close. Why should Opera Mini have 
to send the extra events to tell you nothing happened, and why should authors 
write extra code to look for them anyway (unless they are ignoring the existing 
load that they get today).

On Thu, 01 Feb 2007 08:18:45 +0530, Maciej Stachowiak <mjs@apple.com> wrote:

>
...
> As you can see, to cover all the use cases, "loadstart", a "progress"
> event at the beginning, a "progress" event at the end, and "load" are
> all needed and serve different purposes. And you need the boolean to
> in "progress" to tell you whether the length is determinate or not.
> You cannot overload these for the following reasons:
>
> 1) You can't combine "progress" [0,0,true] and "progress" [0,0,false]
> because: then you don't know whether to flash full (many progress UIs
> like to flash the completed progress bar for at least a moment) or to
> switch to the indeterminat progress bar.

Why do you need start and end events to trigger this? And are you going to rely 
on some perceivable time gap between the progress and the load (or error or...) 
to set the timing of this flash?

> 2) You can't combine "loadstart" with "progress" [0,?,?] because: You
> want to start showing feedback the moment loading starts, even if no
> server response has yet told you what the content length will be, or
> whether it is determinate, but you want to show the total or reflect
> that it is unknown the moment that is the case.

When loading starts you almost certainly don't know the total. If we outlaw 
progress events for zero-length transfers, you get it as [0,0] and it is clear 
you still don't know the total. Alternatively you may get [0,X] and can set up 
the determinate version before you start. But why would you rely on this anyway?

> 3) You can't combine the final "progress" with "load" because: if you
> only have "load", there's no way to know the final total of bytes in
> the indeterminate case,

This is true, if you can't measure the thing you loaded. What is the use case 
for that?

> and if you only have the final "progress",
> you can never tell in the indeterminate case that the load has
> finished. After all, "load" may never happen, you could get "error"
> instead.

Assuming the error is a fatal one, that should be a clear indication that you 
have reached some end, no? Maybe we could come up with a way of programming 
where you try to do something, but have a way of catching errors as well as 
success...

> How the "error" and "loadcancel" events would fit in is left as an
> excercise to the reader; I hope it is obvious that you would need it
> to have a working progress UI driven solely by events, which I think
> is a desirable goal.

I suspect we disagree at the level of where we think the effort should be in UI 
construction. (I can also imagine a use case where there is no UI, and you use 
the progress events to dynamically optimise some set of network operations). 
While both of us are talking about a UI driven solely by events, I believe that 
you can readily build a UI with fewer of them, and that this has the added 
benefit of forcing you to build one that is a bit more backwards-compatible with 
the web as it already is.

> It may sound overengineered to have so many
> events, but it's the only way to make it possible to build correct UI.

We have some of these events already in whatever specification (XHR is an 
example) is going to use progress events. I believe that relying on those makes 
it possible to build correct UI.

cheers

Chaals

> Regards,
> Maciej
>
>
> On Jan 28, 2007, at 1:25 AM, Maciej Stachowiak wrote:
>
>>
>>
>> Hi Chaals,
>>
>> I think to have further fruitful discussion, I think we need to
>> agree on what the use cases for the progress event are. Let me
>> propose what I think is at least one valid use case; if progress
>> events cannot satisfy it, then I hope we can all agree it is
>> insufficient.
>>
>> The use case I propose is as follows: a reusable XBL2 control that
>> shows a progress bar (either determinate or indeterminate), a
>> percentage complete (when applicable), and a display of currently
>> received bytes out of total bytes. It connects to an arbitrary
>> event target via an event listener. I hope we will agree that we
>> want something like this to be possible. This is the kind of very
>> basic progress UI that native applications show, and if it was not
>> correctly doable then clearly progress notification is insufficient.
>>
>> Now, let's consider one aspect of this UI, the progress bar. The
>> progress bar can be in one of three basic states, "disabled",
>> "determinate" (showing progress out of a known total) or
>> "indeterminate" (the barber pole or cylon eye that indicates
>> progress out of an unknown total). When in the determinate state,
>> it has an additional parameter that affects it's display,
>> proportion complete, which goes from 0.0 to 1.0. Fundamentally,
>> this progress bar is a state machine, with state transitions
>> triggered by progress events received.
>>
>> Now, since this control is general, it has to handle any kind of
>> resource you might find on the internet. Just looking at http, this
>> includes all the following cases:
>>
>> A) A resource of known 0 size.
>> B) A resource of known nonzero size.
>> C) A resource of initially unknown size that ends up being 0 size.
>> D) A resource of initially unknown size that ends up being nonzero
>> size.
>>
>> Let's say the progress bar starts in disabled state. As soon as a
>> load starts, you want it to go to either determinate (with some
>> value, maybe 0) or indeterminate. In between, you want the progress
>> bar to update. At the end, you want it to go back to indeterminate
>> state (possibly after a brief pause at 100%). The events need to be
>> able to disambiguate all of these state transitions. In addition,
>> they should be able to handle an error part way through downloading
>> or uploading a resource.
>>
>> Now, let's go back to the issues I raised:
>>
>>
>> On Jan 27, 2007, at 6:21 PM, Charles McCathieNevile wrote:
>>
>>> [Please follow up only to webapi...]
>>>
>>> On Sat, 27 Jan 2007 19:14:24 -0500, Maciej Stachowiak
>>> <mjs@apple.com> wrote:
>>>
>>>>
>>>> On Jan 26, 2007, at 1:54 PM, Charles McCathieNevile wrote:
>>>>
>>>>>
>>>>> Hi,
>>>>>
>>>>> following our face to face meeting, we are planning some changes to
>>>>> progress:
>>>>
>>>> Based on my experience designing the Objective-C API that drives the
>>>> progress bar and other progress indicators in Safari, I think these
>>>> proposed changes make the API unsuitable for common UI use cases.
>>>>
>>>>>
>>>>> 1. Make the "total" attribute 0 if the length is unknown, and drop
>>>>> the boolean "lengthComputable".
>>>>>
>>>>> The rationale is that if you really have a zero-length load, it is
>>>>> unlikely to
>>>>> ever have time to fire a progress event, and will almost certainly
>>>>> only fire any
>>>>> in a really degenerate case. Having a large number was a bad idea,
>>>>> since one day
>>>>> you will have a large number of bytes, and having anegative number
>>>>> meant having
>>>>> a signed instead of unsigned integer.
>>>>
>>>> That means on the first progress event, if there is no data, 0
>>>> progress out of a 0 total is indistinguishable from 0 progress
>>>> out of
>>>> an indeterminate total. I think one common case for these events
>>>> will
>>>> be to drive progress UI. Generally, common user interface toolkits
>>>> have different widgets for indeterminate and determinate progress.
>>>> This way, you can't tell which one to display on the first event.
>>>
>>> Agreed in principle. In practice, we felt that you were unlikely
>>> to get a
>>> progress event with a value 0 except in the indeterminate case -
>>> if you know
>>> that you are transferring 0 of a total of 0 bytes you simply fire
>>> the load event
>>> instead rather than setting up and instantly destroying a transfer
>>> widget. (If
>>> you want to do that, you can do it on load completing if you
>>> hadn't got a
>>> progress event yet...)
>>
>> So does the spec forbid dispatching a 0-current 0-total event when
>> the total is known to be 0? I don't think it does. If it did,
>> though, you would have know way of knowing when the load started
>> for a known-empty resource, and such things do exist. If it
>> doesn't, and your general-purpose progress bar widget receives a
>> 0/0 event, you don't know whether to go to empty determinate
>> progress bar or indeterminate progress bar. And you won't know
>> which is right until the next "load" or "progress" event; in the
>> case of a truly indeterminate resource, which could be a long time.
>>
>> Either way, I think the API would not cover all the needed state
>> transitions.
>>
>>>> But
>>>> on the other hand, the network layer almost always knows the
>>>> total is
>>>> indeterminate very early, so having a "totalKnown" or
>>>> "lengthComputable" boolean or whatever is no great burden.
>>>>
>>>>> 2. Remove the preload and postload events.
>>>>>
>>>>> You know when it finished, because the load event or whatever is
>>>>> spitting out progress will have finished.
>>>>
>>>> Would all things subject to progress events have a "load" event as
>>>> well? If so, I am ok with this. Otherwise, you can't tell when
>>>> something with an indeterminate total is done, so I would object.
>>>
>>> This is the crux of the issue. I would be interested in a use case
>>> for a
>>> progress event that doesn't do this.
>>
>> I'm not sure what you are asking. Progress events spec could be
>> used for anything, and not all of them will necessarily fire a
>> "load" event. For example, in HTML <link rel="stylesheet"
>> href="foo.css"> results in a load but does not, in current UAs,
>> fire a "load" event. If progress events rely on a "load" event to
>> give complete functionality, they should spec it.
>>
>>>
>>>> Note also that many things currently subject to "load" events have
>>>> weird rules for when it does and doesn't fire (as opposed to the
>>>> "error" event or none at all).
>>>>
>>>>> You know when it started, because you got a progress event.
>>>>
>>>> The moment the load starts, the total is not known, and there are 0
>>>> bytes received, but with many protocols (for instance http) you will
>>>> know the total at or before the time the first data chunk is
>>>> received. Given this, I think it's good to have an event that tells
>>>> you when the connection has been initiated, before when you get any
>>>> network response back; the latter should be a progress event.
>>>
>>> Right. That is perfectly in line with what you can do under the
>>> current spec,
>>> but we don't force it...
>>
>> I'm not sure what you are saying is in line with the current spec.
>> Are you saying it is permitted to send a 0/0 event, and then soon
>> after 0/total for some known total? That would be weird. Also, our
>> hypothetical general progress bar control could not rely on it,
>> since, as you say, the spec does not require it. So there would be
>> no way to write interoperable code that made use of this.
>>
>>>
>>>>> 3. Add an uploadprogress
>>>>>
>>>>> It is possible to construct an XHR that is moving content up and
>>>>> down at the
>>>>> same time, so knowing when progress refers to one or the other is
>>>>> useful.
>>>>
>>>> This seems like a good change.
>>>>
>>>>> 4. Rename loadprogress to progress
>>>>>
>>>>> It's shorter.
>>>>
>>>> Seems ok but I wonder whether the event is appropriate for non-
>>>> loading cases of progress, and whether such cases will come up.
>>>
>>> Me too. In principle you might have a script which sends progress
>>> events as it
>>> does some monstrous calculation on a table or something, and it
>>> wouldn't load.
>>> It also wouldn't be transferring bytes. So it might do something
>>> that looks very
>>> similar but is defined seperately. Should we be covering that
>>> range of use case
>>> in this spec, or leave it for authors or a later group to spec out?
>>
>> It would be hard to define a fully general notion of progress. The
>> question is really whether to reserve the generic "progress" name
>> for other things. I don't think it is that important though.
>>
>> Regards,
>> Maciej
>>
>>
>
> 



-- 
Charles McCathieNevile, Opera Software: Standards Group
hablo español - je parle français - jeg lærer norsk
chaals@opera.com Try Opera 9.1 http://opera.com
Received on Tuesday, 6 February 2007 06:19:22 GMT

This archive was generated by hypermail 2.2.0+W3C-0.50 : Tuesday, 8 January 2008 14:18:57 GMT