0

Consider the following HTML code:

<script>setTimeout(() => document.querySelector('link').remove(), 0);</script>
<link rel="stylesheet" href="http://localhost:8080/test.php">

where http://localhost:8080/test.php is a link to a simple PHP script which just waits 5 seconds (<?php sleep(5);).

The script removes the link tag as expected, but browser doesn't abort the request to the stylesheet. This doesn't make sense, because when the request is complete, browser doesn't apply the styles anyway. Is this a browser bug, or is there an explanation for this behavior in the specification?

This happens in Chrome and Firefox; I didn't test other browsers.

Michał Perłakowski
  • 88,409
  • 26
  • 156
  • 177
  • Michal, how browser cancelation of the request should manifest itself? In HTTP there is no way for client to say to the server "stop executing this request on the server", all the client can do is just ignore the response. – SergGr Jun 08 '17 at 19:33
  • @SergGr By "abort" I mean "close the connection with the server". – Michał Perłakowski Jun 08 '17 at 19:36
  • 1
    Michal, then I suspect that this is not implemented because it takes too much effort for so little result. [All features start out with minus 100 points](https://blogs.msdn.microsoft.com/ericgu/2004/01/12/minus-100-points/) – SergGr Jun 08 '17 at 19:59
  • @SergGr My question is mostly about what (if anything) does the specification say about. – Michał Perłakowski Jun 08 '17 at 20:13

2 Answers2

0

In a browser, the layout engine always parses the HTML from top to bottom, sequentially. However, the request to get CSS happens in parallel because CSS never changes the DOM Tree, there is nothing to worry.

Since style sheets don't change the DOM tree, there is no reason to wait for them and stop the document parsing Resource: Read Parsin Scripts > The order of processing scripts and style sheets

The main reason not to abort the CSS request is because it causes no harm. The effort to abort it would be much more painful.

However, note that:

Webkit blocks scripts only when they try to access for certain style properties that may be effected by unloaded style sheets.

Image Credits - http://taligarsiel.com Image: WebKit Layout Engine. Credits - http://taligarsiel.com

Bishwas Mishra
  • 1,235
  • 1
  • 12
  • 25
  • "it causes no harm" – but it does: (1) it [blocks execution of scripts after it](https://stackoverflow.com/q/44375406/3853934) and (2) if the style sheet is big, and you have a poor internet connection, it takes a long time and slows down other downloads. – Michał Perłakowski Jun 10 '17 at 08:12
0

Iv'e been reading up on the HTML Parser and your case seems a bit like the chicken and the egg story because naturally a <script> is supposed to block the parsing execution but there are exceptions to this (async & defer attributes)...

what you are doing is abit different ...

by addressing the document in the script tag the browser is forced to stop parsing and create a document with the tag you are addressing without executing the script itself again in the new document and thus requesting its related content before the DOM is able to remove the element ...

the DOM parsing process in the browser consists of a number of steps :

Overview of the browser parsing model

*If the document.write() method was called from script executing inline (i.e., executing because the parser parsed a set of script tags), then this is a reentrant invocation of the parser.

Edit :

A 'script' element is processed as follows:

  1. If the 'script' element's "already processed" flag is true or if the element is not in the document tree, then no action is performed and these steps are ended.

  2. If the 'script' element references external script content, then the external script content using the current value of the 'xlink:href' attribute is fetched. Further processing of the 'script' element is dependent on the external script content, and will block here until the resource has been fetched or is determined to be an invalid IRI reference.

  3. The 'script' element's "already processed" flag is set to true.

  4. If the script content is inline, or if it is external and was fetched successfully, then the script is executed. Note that at this point, these steps may be re-entrant if the execution of the script results in further 'script' elements being inserted into the document.

Note that a load event is dispatched on a 'script' element once it has been processed, unless it referenced external script content with an invalid IRI reference and 'externalResourcesRequired' was set to 'true'.

The Load Event - The event is triggered at the point at which the user agent (Browser) finishes loading the element and any dependent resources (such as images, style sheets, or scripts). In the case the element references a script, the event will be raised only after an attempt to interpret the script has been made. Dependent resources that fail to load will not prevent this event from firing if the element that referenced them is still in the document tree unless they are designated as externalResourcesRequired. The event is independent of the means by which the element was added to DOM tree.

If you are asking why the event loop is built that way I can't give you a definitive answer nor can I suggest a better way for it to operate but in the comments you asked what the specifications say about this condition and the specifications state that it is due to historical reasons as stated below :

HTML 5.1 W3C Recommendation, 1 November 2016

7. Web application APIs

7.1.4.2. Processing model

Some of the algorithms in this specification, for historical reasons, require the user agent to pause while running a task until a condition goal is met. This means running the following steps:

  1. If necessary, update the rendering or user interface of any Document or browsing context to reflect the current state.
  2. Wait until the condition goal is met. While a user agent has a paused task, the corresponding event loop must not run further tasks, and any script in the currently running task must block. User agents should remain responsive to user input while paused, however, albeit in a reduced capacity since the event loop will not be doing anything.
Gal Ratzkin
  • 124
  • 2
  • 8