Skip to content

Instantly share code, notes, and snippets.

@latentflip
Last active April 26, 2016 23:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save latentflip/01b64dc4da36d74376c46e25e0e3b68a to your computer and use it in GitHub Desktop.
Save latentflip/01b64dc4da36d74376c46e25e0e3b68a to your computer and use it in GitHub Desktop.

Philip, I recently watched your youtube video on the event loop and found it to be very informative. In one of your examples it has a setTimout(...,0) and is followed by two console logs. Being that the setTimeout is a web API it is sent to the callback queue and finally to the call stack (once it has been cleared of the two console.logs). My confusion lies with the fact that console is a web API as show here(https://developer.mozilla.org/en-US/docs/Web/API) in the MDN. If console is a web API then doesn't it go to the task/callback queue just like setTimeout?

Thank you,

So the confusion is probably just because I glossed over the difference between an asynchronous web api, and a synchronous one.

The distinction between calling a "normal" JavaScript function (say Math.floor(5.5)) and one provided by a web api (like console.log('foo') or setTimeout(..., 0)) isn't solely about whether it's async (and so appears on the callback queue) or not.

Really the difference is whether it's a part of the language "runtime", or it's provided by the host environment (e.g. the browser). There are many many functions defined by Web APIs (as found in that list) that exist and are provided by the browser, rather than v8 itself. For example, node.js, which uses v8 but wraps it in a js-on-the-server "framework", rather than wrapping it in a "browser" lacks most of the things in that Web API list (e.g. there's no document.getElementById in node).

Additionally, some of the functions provided by the host environment (node/browser Web APIs) may be asynchronous, but they don't have to be. Ultimately you have a range of combinations:

  • "runtime" and synchronous - defined by the runtime, and returns synchronously (Math.floor(5.5))
  • "web api" and synchronous, no return value (console.log('hi'))
  • "web api" and synchronous, with a return value (document.getElementById('foo'))
  • ** "web api" and asynchronous, with no callback** (this is conceivable, i.e. the api code you are calling will happen "at some point in the future" but it has no need to callback into the JavaScript runtime. I can't think of an example off the top of my head, other than functions which take an optional callback, e.g. making an ajax request where you don't care about the response)
  • "web api" and asynchronous, with a callback (setTimeout(function () {console.log('ran')}, 100))

As you can see, there are a number of "web api" calls, which don't need to do work asynchronously and pass some result back to JavaScript land, or call some function in JavaScript land when they are done. If they don't need to do both of those things, the callback queue/event loop part of the cycle isn't used.

Most of the time you can tell whether a "web api" will use the callback queue, if it takes a callback function (that will be called asynchronously). If a "web api" function call actually returns a value, then that value must have been returned synchronously. Conversely, if a "web api" wants to do async work and pass the result back to JS, then it _must _use the callback queue.

There are many reasons why a web api may be made to be synchronous or asynchronous. Ultimately the decision's going to come down to a) performance, and b) usability. If it's going to take a potentially long time to do something (like making a network request), then that web api is almost certainly going to be asynchronous (for example ajax requests), because making it synchronous would completely block the browser (as shown in my talk). However, if it's going to be fast enough like document.getElementById then making it synchronous makes developer's lives easier as they don't have to deal with callbacks.

Often these are in conflict with each other - for example, JSON.parse is synchronous, which makes life simpler, and often it's fast enough that that's okay. But in performance sensitive applications, or where you are trying to parse large amounts of json on a lower powered device (smartphone), it would be nice if there was an async variant, to avoid locking the browser while that work's happening. Unfortunately, for now, history has dictated that JSON.parse is synchronous, so that's what we're stuck with (though people are finding hacks to achieve it non-blocking-async-json-parse.html).

In the specific case of console.log - first of all, it doesn't return a value that you care about, so even if it was asynchronous it wouldn't necessarily use the callback queue anyway (as you would have no reason to give it a callback). It may even_be_ asynchronous in some implementations, to be honest you'd be hard pressed to tell the difference. But I'm fairly certain in most situations it is synchronous, which basically means that:

1. var a = 2;
2. console.log('hi')
3. console.log('bye')
4. a = 5;

in this example, lines 2 and 3 are guaranteed to have executed and logged to your console before line 4 happens, and they are guaranteed to print in the correct order.

Hope that covers everything!

@radrad
Copy link

radrad commented Apr 26, 2016

Hi Philip. Thank you for further clarifying this.
I was wondering if you manage to provide XHR shim for your loupe tool.
I would like to know if I can use the tool with Angular 2 application and if there is a way to "blackbox" some script calls so I only get visualization for my custom code (written in TypeScript and transpiled in.js)..
Tx
Rad

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment