On Thu, Jan 21, 2010 at 8:56 PM, Darin Fisher <span dir="ltr"><<a href="mailto:darin@chromium.org">darin@chromium.org</a>></span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="im">On Thu, Jan 21, 2010 at 7:17 PM, Brady Eidson <span dir="ltr"><<a href="mailto:beidson@apple.com" target="_blank">beidson@apple.com</a>></span> wrote:<br></div><div class="gmail_quote"><div class="im">
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><br>
On Jan 21, 2010, at 1:12 AM, Darin Fisher wrote:<br>
<br>
</div><div>> In WebKit, history.back() is currently implemented asynchronously.<br>
><br>
> However, it was not always this way.  Previously, if the back navigation corresponded to a hash change, then the back navigation would complete synchronously.  If the back navigation corresponded to a different document, then it would be completed asynchronously.<br>


><br>
> The HTML5 spec currently calls for the old behavior of WebKit, which happens to match the behavior of Gecko.  Because the spec is written this way, there is movement in WebKit to change WebKit back.<br>
><br>
> IE however appears to implement history.back() asynchronously in all cases just like newer versions of WebKit.<br>
><br>
> I actually think this is a better behavior to spec for a couple reasons:<br>
><br>
> 1)  It allows for history.back() to behave consistently regardless of the type of navigation.<br>
<br>
</div>I agree it would make history.back() consistent regardless of the type of navigation.  I don't necessarily know what benefit this has.<br></blockquote><div><br></div></div><div>Please see my note to Maciej regarding this.</div>
<div class="im">
<div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><br>
> 2)  It allows for the back/forward list to be decoupled from the main thread of the rendering engine.<br>
<br>
</div>I've both brainstormed on my own and discussed this point with others who have done a lot of thought on how a multi-threaded or multi-processed WebKit may work in the future, and we all agree that synchronous history.go() does not make an MT/MP implementation difficult or impossible.<br>

</blockquote><div><br></div></div><div>Yes, I can imagine some MT/MP implementations where that could be true.</div><div><br></div><div>However, as someone with a great deal of experience developing a multi-process browser, I can tell you that this would be very expensive for us to support.  We heavily leverage the fact that the session history list is divorced from the rendering process / thread.  For example, session history is modified outside of the rendering process.</div>
<div class="im">
<div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><br>
> This last point is quite relevant to Chrome since we store the back/forward list in a separate process.  We do this since items in the back/forward list may actually need to be rendered using different WebKit processes.  (Navigating in the location bar is a hint that we can spawn a new process.)<br>


><br>
> We could copy the entire back/forward list to each process and replicate state, but that seems excessive.  Instead, simply matching the history.back() behavior of IE avoids the need to do so.<br>
><br>
> From a web compat perspective, it seems wise to match the behavior of IE.<br>
<br>
</div>This is often the case, yes, but not always a good enough rationalization on its own.<br></blockquote><div><br></div></div><div>Sure, and it is not the only reason.</div><div class="im"><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">


<div><br>
> It also has other benefits.<br>
<br>
> Can we change the spec?<br>
<br>
</div>I've heard one concrete benefit and one theoretical benefit.<br>
Concrete - Chrome's particular multi-process model easily fits in with asynchronous history.go()<br>
Theoretical - Matching the behavior of IE here is important to compatibility than matching Gecko and previous Webkit behavior.<br></blockquote><div><br></div></div><div>There is also the consistency argument I made.  That is quite a concrete benefit for programmers.</div>
<div class="im">
<div><br></div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
To argue in favor of the current spec:<br>
<br>
One of the main drives for async behavior in modern programming and HTML 5 specifically has been to remove the slow and unpredictable nature of blocking I/O from the equation.  Certainly that has been a motivating factor in a lot of feedback I have given, others at Apple have given, and many outside of Apple have given to the HTML 5 spec (including those who work on Chromium).<br>

</blockquote><div><br></div></div><div>Yes, that is a huge motivation.  I believe there are other motivations.  For example, asynchronous events provide a nice means to avoid re-entrancy and the deeply nested stacks that come with them.  postMessage is asynchronous for this reason.  The scroll event is spec'd to be asynchronous for similar reasons.</div>
<div class="im">
<div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
The current synchronous traversals called for by the spec are explicitly the ones that - from the engine's standpoint - will never have i/o to block on.<br>
<br>
More generally, asynchronicity adds complexity to using and understanding APIs as well as predicting the side effects of a particular method call.  Web developers rarely - if ever - have sympathy for the difficulties of the engineers who created the environment they are working in.<br>


<br>
It seems that when designing and presenting an API, synchronicity should be preferred unless there's an inherent performance or scalability problem with it.  And I just don't see that problem with the specified behavior of history.go().<br>

</blockquote><div><br></div><div><br></div></div><div>Again, there is a consistency problem, a re-entrancy problem, etc.</div><div><br></div><div>From the performance and scalability angle, I also believe that we should not design ourselves into a corner with APIs.  I for one am very interested in a future where more elements of an application can be split off into separate threads.  An iframe in a separate domain being a good example where this kind of separation is desirable.  The more synchronous events we build into the platform (binding everything together), the more we do to defeat a nice future where more things can be run independently on separate threads.</div>

<div><br></div><div>Imagine the case of a frame in domain A containing a frame in domain B.  They cannot directly script each other.  They can only communicate using postMessage.  That's nice because it allows them to run independently.  Now, imagine that the subframe navigates itself to a reference fragment.  Why should history.back() called by the parent frame result in blocking the parent until the subframe traversal completes?</div>

<div><br></div></div></blockquote><div><br></div><div>Another performance consideration:</div><div><br></div><div>Suppose I wanted to have a near endless session history.  To implement that I'm very likely to use a disk-based backing store, which could imply having to block the UI thread of a web app in order to read from disk.  That is bad.</div>
<div><br></div><div>-Darin</div><div><br></div><div><br></div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><div class="gmail_quote"><div>
</div><div>-Darin</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
~Brady<br>
<br>
><br>
> -Darin<br>
<br>
</blockquote></div><br>
</blockquote></div><br>