惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Full Disclosure
Stack Overflow Blog
Stack Overflow Blog
H
Help Net Security
Microsoft Azure Blog
Microsoft Azure Blog
The GitHub Blog
The GitHub Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Recorded Future
Recorded Future
Y
Y Combinator Blog
Cloudbric
Cloudbric
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
S
Schneier on Security
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
C
Cybersecurity and Infrastructure Security Agency CISA
TaoSecurity Blog
TaoSecurity Blog
Security Latest
Security Latest
N
News and Events Feed by Topic
Hacker News - Newest:
Hacker News - Newest: "LLM"
D
DataBreaches.Net
Security Archives - TechRepublic
Security Archives - TechRepublic
H
Hacker News: Front Page
C
Cisco Blogs
L
LangChain Blog
aimingoo的专栏
aimingoo的专栏
Recent Commits to openclaw:main
Recent Commits to openclaw:main
V
Vulnerabilities – Threatpost
L
LINUX DO - 最新话题
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Google Online Security Blog
Google Online Security Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
A
About on SuperTechFans
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Jina AI
Jina AI
C
CXSECURITY Database RSS Feed - CXSecurity.com
Schneier on Security
Schneier on Security
T
Tenable Blog
N
News and Events Feed by Topic
W
WeLiveSecurity
有赞技术团队
有赞技术团队
AI
AI
爱范儿
爱范儿
大猫的无限游戏
大猫的无限游戏
Latest news
Latest news
T
The Blog of Author Tim Ferriss
S
Security Affairs
Know Your Adversary
Know Your Adversary
Simon Willison's Weblog
Simon Willison's Weblog
G
GRAHAM CLULEY
Google DeepMind News
Google DeepMind News
The Cloudflare Blog

Mathias Bynens

A horrifying globalThis polyfill in universal JavaScript JavaScript engine fundamentals: optimizing prototypes JavaScript engine fundamentals: Shapes and Inline Caches Asynchronous stack traces: why await beats Promise#then() ECMAScript regular expressions are getting better! Unicode property escapes in JavaScript regular expressions ES2015 const is not about immutability Valid JavaScript variable names in ES2015 Unicode-aware regular expressions in ES2015 Dear Google, please fix plain text emails in Gmail PBKDF2+HMAC hash collisions explained JavaScript has a Unicode problem Processing Content Security Policy violation reports Hiding JSON-formatted data in the DOM with CSP enabled Loading JSON-formatted data with Ajax and xhr.responseType='json' Reserved keywords in JavaScript How to support full Unicode in MySQL databases How to speedrun Dropbox’s Dropquest 2012 Unquoted font family names in CSS Unquoted property names / object keys in JavaScript Valid JavaScript variable names in ES5 CSS character escape sequences JavaScript’s internal character encoding: UCS-2 or UTF-16? The smallest possible valid (X)HTML documents JavaScript character escape sequences JavaScript foo.prototype.bar notation Ambiguous ampersands HTML element + attribute notation How I detect and use localStorage: a simple JavaScript pattern Unquoted attribute values in HTML and CSS/JS selectors The end-tag open (ETAGO) delimiter Using the oninput event handler with onkeyup/onkeydown as its fallback Everything you always wanted to know about touch icons In defense of CSS hacks — introducing “safe CSS hacks” AirPlay video support in iOS Safari — a bookmarklet Completing Dropbox’s Dropquest 2011 in 60 seconds Using CSS without HTML How to create simple Mac apps from shell scripts Bulletproof JavaScript benchmarks Thoughts on Safari Reader’s generated HTML How to enable Safari Reader on your site? The XML serialization of HTML5, aka ‘XHTML5’ The id attribute got more classy in HTML5 The three levels of HTML5 usage The HTML5 document.head DOM tree accessor Bulletproof HTML5 <details> fallback using jQuery Displaying hidden elements like <head> using CSS Inline <script> and <style> vs. external .js and .css — what’s the size threshold? Using Showdown/PageDown with and without jQuery
Using setTimeout to speed up window.onload
Mathias · 2010-09-08 · via Mathias Bynens

A few days ago, Martín Borthiry contacted me with a question. He had been using the optimized asynchronous Google Analytics snippet for a while, and noticed an additional speed gain when wrapping it inside a setTimeout() with a delay of 0 milliseconds. His tests made it pretty clear that this technique was indeed slightly faster, but Martín had no clue why.

The answer to his question is simple: JavaScript code inside setTimeout() doesn’t necessarily delay the onload event. Consider the following test case:

<!DOCTYPE html>
<meta charset="utf-8">
<title>setTimeout() and window.onload</title>
<script>

	setTimeout(function() {
		document.body.style.background = 'red';
	}, 3000);

	window.onload = function() {
		document.body.style.background = 'green';
	};

</script>

Here’s what happens when you open this document:

  1. The browser’s HTML parser does its thing, but halts as soon as it encounters the opening <script> tag.
  2. The contents of the <script> element are executed. The setTimeout will cause some other code to run in 3 seconds, and an event handler is bound to window.onload.
  3. The HTML parser continues parsing the document until the end.
  4. Since there are no other resources on this page, the onload event fires as soon as the parser is finished.
  5. The window.onload event handler is invoked. The document gets a green background.
  6. About 3 seconds later, the setTimeout function kicks in. The document gets a red background.

In this example, using setTimeout doesn’t delay the onload event. Note that this is not necessarily the case for other scenarios! For example, consider the following document:

<!DOCTYPE html>
<meta charset="utf-8">
<title>setTimeout() and window.onload</title>
<img src="image.png">
<script>

	setTimeout(function() {
		document.body.style.background = 'red';
	}, 3000);

	window.onload = function() {
		document.body.style.background = 'green';
	};

</script>

As you can see, we’ve added an image to the document. (Of course, this could be any other resource that blocks onload.) The onload event won’t fire before the image is fully loaded.

This gives us a slightly different result:

  1. The browser’s HTML parser starts parsin’ away.
  2. The browser starts downloading the image as soon as the <img> element is parsed.
  3. The parser halts as soon as it encounters the opening <script> tag.
  4. The contents of the <script> element are executed. The setTimeout will cause some other code to run in 3 seconds, and an event handler is bound to window.onload.
  5. The HTML parser continues parsing the document until the end.
  6. As soon as the image is fully loaded, the onload event fires.
  7. The window.onload event handler is invoked. The document gets a green background.

As you can see, one step is missing from this list, simply because there’s no way to accurately predict where it should go. The code within the setTimeout will be executed 3 seconds after step 4, we know that much. But depending on how long it takes to download the image, this could be before or after onload.

Let’s say the image takes 1 second to load. This means the onload event will fire after about a second, too. Two seconds later, the code in the setTimeout will finally get executed.

If the image takes 5 seconds to load, the onload event will again be delayed during that time, so the code in the setTimeout will be executed before onload.

What would happen if the image takes about 3 seconds to load, i.e. the delay parameter for the setTimeout? Will onload fire before, during, or after the code in the setTimeout?

To answer that question, you need to understand that JavaScript is single threaded. If there’s some code that is running (either from an inline script or from inside the setTimeout) at the time that the browser is ready to fire onload, the browser will have to ‘wait’ until the script is finished before onload is processed. Similarly, if you use setTimeout to download resources, and they enter the download queue before onload fires, then loading these resources will (still) delay onload. (Thanks to Kyle Simpson for explaining this in detail to me!)

In other words, using setTimeout does not guarantee to speed up the onload event in all cases. But most of the time, it will.

Useful?

This means we can use the setTimeout(fn, 0) pattern to prevent delaying the onload event, causing the perceived load/rendering time to decrease. Of course, this technique can only be used for scripts that aren’t dependencies.

I think tracking scripts make a good example. Most of those insert a new <script> element into the DOM dynamically. As you know, every DOM operation comes with a certain performance penalty. The default Google Analytics code, for example, will modify the DOM as soon as the snippet is encountered, therefore delaying the onload event.

Here’s a modified version of my asynchronous Google Analytics snippet, using setTimeout to prevent delaying onload:

<script>
	var _gaq = [['_setAccount', 'UA-XXXXX-X'], ['_trackPageview']];
	setTimeout(function() {
		var g = document.createElement('script'),
		    s = document.scripts[0];
		g.src = 'https://ssl.google-analytics.com/ga.js';
		s.parentNode.insertBefore(g, s);
	}, 0);
</script>

(Note that this is basically what Martín’s article is all about. Go check it out!)

Some caveats

As mentioned before, this technique cannot be used for scripts that are dependencies. It’s not very predictable when exactly the fn inside setTimeout(fn, 0) will be executed. If you had two or three of these constructions, there’d be no way to tell in which order they execute.

Also note that the this binding of the function inside setTimeout is automatically overridden to the global window object. This may break scripts that rely on this referring to something else at that point.

Note that the smallest setTimeout timeout value allowed by the HTML5 specification is 4 ms. Smaller values (like 0) should clamp to 4 ms. You can test which browsers follow the spec in this regard here.

Thoughts?

I really feel like this needs further investigation. I’d love to hear what you think in the comments!