Differences between requestIdleCallback and setImmediate? - javascript

There are currently 2 different API's aimed at breaking tasks up into scheduled callback functions.
setImmediate (non-standard)
requestIdleCallback (experimental)
To my knowledge there are no JavaScript runtimes (browser or Node) which currently implement both features.
I would like to better understand how the two features compare. I realize that requestIdleCallback has a timeout option which can be used to allow the browser to decide when to call it, and passes a IdleDeadline object to the callback where setImmediate passed any supplied arguments, but other than that how do these API's differ?
For example, are the following two examples functionally identical?
setImmediate(function() {
// Do something.
});
requestIdleCallback(function() {
// Do something.
}, {timeout: 0});
What about in the case where multiple callbacks are registered but the first one runs longer than the idle time?

setTimeout will wait for a time to pass, then it will execute the callback.
requestIdleCallback will wait for the main thread to be idle before executing the callback. Meaning that it won't slow animations, user can still click buttons and type into inputs.
How to choose between setTimeout and requestIdleCallback? setTimeout is best used when the callback must execute (Example: Sending data to an analytics server or logging out the user). requestIdleCallback is best for when you don't want to hurt the user experience in the cost of executing the callback (Example: Rerendering the DOM).
Keep in mind that requestIdleCallback is still experimental.

requestIdleCallback won't execute when document.visibilityState === 'hidden', it will execute all callback at once when it become visible.
At least in electron's browser view.

Related

How does JavaScript insure `setTimeout()` can register given function to microtask queue when delay timer expires?

I know JavaScript has macrotasks and microtasks.
And I know setTimeout(()=>{console.log(1)}, 1000) means register the given function to microtask queue after 1000 milli-seconds.
My questions is how does JavaScript insure this?
When setTimeout(funcRef, delay)'s delay expires, will it raise an event or an interruption that JavaScript will handle it immediately?
Where can I get these details?
When setTimeout(funcRef, delay)'s delay expires, will it raise an event or an interruption that JavaScript will handle it immediately?
Timers in Javascript are purely event driven, not interrupt driven. So, it will NOT interrupt any code that is currently running. Instead, the code that was running will continue until it returns control back to the event loop at which point one part of the event loop is to check if a timer's time has been reached so its callback should be called.
The internal details of how timers work is implementation-specific. The structure (and code) for nodejs are completely public and there have been many articles written about how timers work in the event loop in libuv in nodejs and the libuv code that implements it all is all available to examine. Here's one nodejs article and a nodejs timing example is covered in this other answer.
Because of the single-threaded, event-driven nature of the Javascript implementations in nodejs and browsers, timer callbacks are run on a best-effort basis with no guarantees for timing accuracy. All that is guaranteed is that the timer callback will be called sometime AFTER it's scheduled time. If the interpreter is busy for awhile, the timer might be called quite late. And, as Pointy mentioned, the browser deprioritizes timers in background tabs/windows and timers may be run even later than usual. Interval timers may even skip entire cycles in the browser environment.
Keep in mind that timers are not part of the Javascript/ECMAscript specification. They are a feature offered by the host environment that is not in the language specification. As such, you are not guaranteed that all details of the implementation will be identical in different environments (for example, nodejs vs. browser).
In particular, there are some implementation oddities/differences around setTimeout(fn, 0). It appears that Chrome schedules a setTimeout(fn, 0) before any other timers that are already in the queue (sometimes), even if the other timers are already past their time to fire, but nodejs does not. Ideally, you would not write code that depends upon this level of nuance. See this answer for more discussion of the setTimeout(fn, 0) oddities.

How is timing of `setImmediate()` and `setTimeout()` bound by the performance of the process?

I am confused by the following paragraph of the Node.js documentation.
setImmediate() vs setTimeout()
... The order in which the timers are executed will vary depending on the context in which they are called. If both are called from within the main module, then timing will be bound by the performance of the process (which can be impacted by other applications running on the machine).
For example, if we run the following script which is not within an I/O cycle (i.e. the main module), the order in which the two timers are executed is non-deterministic, as it is bound by the performance of the process:
It proceeds to show the following example
// timeout_vs_immediate.js
setTimeout(() => {
console.log('timeout');
}, 0);
setImmediate(() => {
console.log('immediate');
});
$ node timeout_vs_immediate.js
timeout
immediate
$ node timeout_vs_immediate.js
immediate
timeout
I don't understand what makes the result non-deterministic. Since the timers phase happens before the check phase, shouldn't the callbacks scheduled by setTimeout always execute before those scheduled by setImmediate? I don't think the order of the phases in the event loop would change due to a context switch or something.
The document also states that
However, if you move the two calls within an I/O cycle, the immediate callback is always executed first:
OK, but what makes so-called "I/O cycles" different from the main module?
I know there are a lot of related questions, but all answers merely state this fact by citing the documentation, without explaining where the non-determinism comes into play, so I don't think this is a duplicate.
The actual trick is in the Timeout constructor which is called by setTimeout and which increases times below 1 to 1. Thus setTimeout(fn, 0) is actually equivalent to setTimeout(fn, 1).
When libuv initializes, it starts with timers after updating its internal clock, and when one millisecond already passed till then it's gonna pick up the timer before proceeding to the poll phase (which is followed by the setImmediate phase).
Another interesting observation is that multiple timers might also run before and after setImmeadiate:
setTimeout(() => console.log('timer'), 1);
setTimeout(() => console.log('timer'), 1);
setImmediate(() => console.log('immediate'));
// can produce:
// timer
// immediate
// timer
That's because setTimeout calls getLibuvNow internally, which will call env->GetNow() and which not only gets the current time of libuv, but also updates it. Thus it might happen that the timer get put into the timer queue with different due times, and thus the timer phase will only pick up some of them.
OK, but what makes so-called "I/O cycles" different from the main module?
The main module gets run before libuv is initialized, whereas most other code will run in the poll phase of the libuv loop. Thus the main module initialization is followed by the timer phase, whereas the poll phase is followed by the 'check handles' phase, which among others runs the setImmediate callbacks. Thus usually in the main module timers would run before immediates (if they're due) and if scheduled in callbacks, immediates would run before timers.
I'll write an aswer as well for visibility, since it's a good question and node documentation indeed is misleading and I had to dig a bit to find some resources as well...
This question was answered here (accepted answer) very well with a performance benchmark testing..
But the actual explaination can be found in another answer that points to this article which explains the event loop better.
Also, read this answer (this one is the best one, it goes through the internal code and explains which section is platform dependant and time consuming of the CPU and generates the non-determinism and also the fact that 0 is transformed into 1 internally for setTimeout) to an issue raised on nodejs asking the same question which seems to explain it even further.
One more important things to note is setTimeout when set to 0 is internally converted to 1.
This call to uv__hrtime is platform dependent and is cpu-time-consuming work as it makes system
call to clock_gettime. It's is impacted by other application running on the machine.
If the preparation before the first loop took more than 1ms then the Timer Phase calls the callback associated with it. If it's is less than 1ms Event-loop continues to next phase and runs the setImmediate callback in check phase of the loop and setTimeout in the
next tick of the loop.

What is the difference between the event loop in JavaScript and async non-blocking I/O in Node.js?

In this answer to the question -
What is non-blocking or asynchronous I/O in Node.js?
the description sounds no different from the event loop in vanilla js. Is there a difference between the two? If not, is the Event loop simply re-branded as "Asynchronous non-blocking I/O" to sell Node.js over other options more easily?
The event loop is the mechanism. Asynchronous I/O is the goal.
Asynchronous I/O is a style of programming in which I/O calls do not wait for the operation to complete before returning, but merely arrange for the caller to be notified when that happens, and for the result to be returned somewhere. In JavaScript, the notification is usually performed by invoking a callback or resolving a promise. As far as the programmer is concerned, it doesn’t matter how this happens: it just does. I request the operation, and when it’s done, I get notified about it.
An event loop is how this is usually achieved. The thing is, in most JavaScript implementations, there is literally a loop somewhere that ultimately boils down to:
while (poll_event(&ev)) {
dispatch_event(&ev);
}
Performing an asynchronous operation is then done by arranging for the completion of the operation to be received as an event by that loop, and having it dispatch to a callback of the caller’s choice.
There are ways to achieve asynchronous programming not based on an event loop, for example using threads and condition variables. But historical reasons make this programming style quite difficult to realise in JavaScript. So in practice, the predominant implementation of asynchrony in JavaScript is based on dispatching callbacks from a global event loop.
Put another way, ‘the event loop’ describes what the host does, while ‘asynchronous I/O’ describes what the programmer does.
From a non-programmer’s bird’s eye view this may seem like splitting hairs, but the distinction can be occasionally important.
There are 2 different Event Loops:
Browser Event Loop
NodeJS Event Loop
Browser Event Loop
The Event Loop is a process that runs continually, executing any task queued. It has multiple task sources which guarantees execution order within that source, but the Browser gets to pick which source to take a task from on each turn of the loop. This allows Browser to give preference to performance sensitive tasks such as user-input.
There are a few different steps that Browser Event Loop checks continuously:
Task Queue - There can be multiple task queues. Browser can execute queues in any order they like. Tasks in the same queue must be executed in the order they arrived, first in - first out. Tasks execute in order, and the Browser may render between tasks. Task from the same source must go in the same queue. The important thing is that task is going to run from start to finish. After each task, Event Loop will go to Microtask Queue and do all tasks from there.
Microtasks Queue - The microtask queue is processed at the end of each task. Any additional microtasks queued during during microtasks are added to the end of the queue and are also processed.
Animation Callback Queue - The animation callback queue is processed before pixels repaint. All animation tasks from the queue will be processed, but any additional animation tasks queued during animation tasks will be scheduled for the next frame.
Rendering Pipeline - In this step, rendering will happen. The Browser gets to decide when to do this and it tried to be as efficient as possible. The rendering steps only happen if there is something actually worth updating. The majority of screens update at a set frequency, in most cases 60 times a second (60Hz). So, if we would change page style 1000 times a second, rendering steps would not get processed 1000 times a second, but instead it would synchronize itself with the display and only render up to a frequency display is capable of.
Important thing to mention are Web APIs, that are effectively threads. So, for example setTimeout() is an API provided to us by Browser. When you call setTimeout() Web API would take over and process it, and it will return the result to the main thread as a new task in a task queue.
The best video I found that describes how Event Loops works is this one. It helped me a lot when I was investigating how Event Loop works. Another great videos are this one and this one. You should definitely check all of them.
NodeJS Event Loop
NodeJS Event Loop allows NodeJS to perform non-blocking operations by offloading operation to the system kernel whenever possible. Most modern kernels are multi-threaded and they can perform multiple operations in the background. When one of these operations completes, the kernel tells NodeJS.
Library that provides the Event Loop to NodeJS is called Libuv. It will by default create something called Thread Pool with 4 threads to offload asynchronous work to. If you want, you can also change the number of threads in the Thread Pool.
NodeJS Event Loop goes through different phases:
timers - this phase executes callbacks scheduled by setTimeout() and setInterval().
pending callbacks - executes I/O callbacks deferred to the next loop iteration.
idle, prepare - only used internally.
poll - retrieve new I/O events; execute I/O related callbacks (almost all with the exception of close callbacks, the ones scheduled by timers, and setImmediate()) Node will block here when appropriate.
check - setImmediate() callbacks are invoked here.
close callbacks - some close callbacks, e.g. socket.on('close', ...).
Between each run of the event loop, Node.js checks if it is waiting for any asynchronous I/O or timers and shuts down cleanly if there are not any.
In Browser, we had Web APIs. In NodeJS, we have C++ APIs with the same rule.
I found this video to be useful if you want to check for more information.
For years, JavaScript has been limited to client-side applications
such as interactive web applications that run on the browser. Using
NodeJS, JavaScript can be used to develop server-side applications as
well. Though it’s the same programming language which is used in both
use cases, client-side and server-side have different requirements.
“Event Loop” is a generic programming pattern and JavaScript/NodeJS
event loops are no different. The event loop continuously watches for
any queued event handlers and will process them accordingly.
The “Events”, in a browser’s context, are user interactions on web
pages (e.g, clicks, mouse movements, keyboard events etc.), but in
Node’s context, events are asynchronous server-side operations (e.g,
File I/O access, Network I/O etc.)

Multithreading javascript

I want to create a real thread which manages some operations in javascript.
After several search, i found 'Web Workers', 'setTimeout' or 'setInterval'.
The problem is that 'Web Workers' don't have access to global variables and therefore can't modify my global arrays directly (or i do not know how).
'setTimeout' is not really what i need.
'setInterval' sets my problem, however it is probably that after many times my operations could last longer. Therefore i am afraid that two interval overlaps.
Finally i need a infinite loop which executes a series of operations once after another. Does it exist or do I have to content myself with 'setInterval'? Is there an alternative with jQuery or other? If it is not, is what I can expect in the near future to see the developer make it available?
I'm going to assume you're talking about in a web browser.
JavaScript in web browsers has a single main UI thread, and then zero or more web worker threads. Web workers are indeed isolated from the main UI thread (and each other) and so don't have access to globals (other than their own). This is intentional, it makes both implementing the environment and using it dramatically simpler and less error-prone. (Even if that isolation weren't enforced, it's good practice for multi-threaded programming anyway.) You send messages to, and receive messages from, web workers via postMessage and the message event.
JavaScript threads (the main UI thread and any web workers) work via a thread-specific task queue (aka "job queue"): Anything that needs to happen on a JavaScript thread (the initial run of the code when a page loads, handling of an event, timer callbacks [more below]) adds a task to the queue. The JavaScript engine runs a loop: Pick up the next task, run it, pick up the next, run it, etc. When there are no tasks, the thread goes quiet waiting for a task to arrive.
setTimeout doesn't create a separate thread, it just schedules a task (a call to a callback) to be added to the task queue for that same thread after a delay (the timeout). Once the timeout occurs, the task is queued, and when the task reaches the front of the queue the thread will handle it.
setInterval does exactly what setTimeout does, but schedules a recurring callback: Once the timeout occurs, it queues the task, then sets up another timeout to queue the task again later. (The rules around the timing are a bit complex.)
If you just want something to recur, forever, at intervals, and you want that thing to have access to global variables in the main UI thread, then you either:
Use setInterval once, which will set up recurring calls back to your code, or
Use setTimeout, and every time you get your callback, use setTimeout again to schedule the next one.
From your description, it sounds as though you may be calling setInterval more than once (for instance, on each callback), which quickly bogs down the thread as you're constantly telling it to do more and more work.
The last thing is easy: webworker start their work when they get a message to (onmessage) and sit idle otherwise. (that's highly simplified, of course).
Global variables are not good for real multi-threading and even worse with the reduced thing JavaScript offers. You have to rewrite your workers to work standalone with only the information given.
Subworkers have a messaging system which you might be able to make good use of.
But the main problem with JavaScript is: once asynchronous always asynchronous. There is no way to "join" threads or a "wait4" or something similar. The only thing that can do both is the XMLHttprequest, so you can do it over a webserver but I doubt the lag that causes would do any good. BTW: synchronous XMLHttprequest is deprecated says Mozilla which also has a page listing all of the way where a synchronous request is necessary or at least very useful.

JavaScript and single-threadedness

I always hear that JavaScript is single-threaded; that when JavaScript is executed, it's all run in the same global mosh pit, all in a single thread.
While that may be true, that single execution thread may spawn new threads, asynchronousy reqeiving data back to the main thread, correct? For example, when an XMLHttpRequest is sent, doesn't the browser create a new thread that performs the HTTP transaction, then invoke callbacks back in the main thread when the XMLHttpRequest returns?
What about timers--setTimeout and setInterval? How do those work?
Is this single-threadedness the result of the language? What has stopped JavaScript from having multi-threaded execution before the new Web Workers draft?
XMLHttpRequest, notably, does not block the current thread. However, its specifics within the runtime are not outlined in any specification. It may run in a separate thread or within the current thread, making use of non-blocking I/O.
setTimeout and setInterval set timers that, when run down to zero, add an item for execution, either a line of code of a function/callback, to the execution stack, starting the JavaScript engine if code execution has stopped. In other words, they tell the JavaScript engine to do something after it has finished doing whatever it's doing currently. To see this in action, set multiple setTimeout(s) within one method and call it.
Your JavaScript itself is single-threaded. It may, however, interact with other threads in the browser (which is frequently written with something like C and C++). This is how asynchronous XHR's work. The browser may create a new thread (or it may re-use an existing one with an event loop.)
Timers and intervals will try to make your JavaScript run later, but if you have a while(1){ ; } running don't expect a timer or interval to interrupt it.
(edit: left something out.)
The single-threadedness is largely a result of the ECMA specification. There's really no language constructs for dealing with multiple threads. It wouldn't be impossible to write a JavaScript interpreter with multiple threads and the tools to interact with them, but no one really does that. Certainly no one will do it in a web browser; it would mess everything up. (If you're doing something server-side like Node.js, you'll see that they have eschewed multithreading in the JavaScript proper in favor of a snazzy event loop, and optional multi-processing.)
See this post for a description of how the javascript event queue works, including how it's related to ajax calls.
The browser certainly uses at least one native OS thread/process to handle the actual interface to the OS to retrieve system events (mouse, keyboard, timers, network events, etc...). Whether there is more than one native OS-level thread is dependent upon the browser implementation and isn't really relevant to Javascript behavior. All events from the outside world go through the javascript event queue and no event is processed until a previous javascript thread of execution is completed and the next event is then pulled from the queue given to the javascript engine.
Browser may have other threads to do the job but your Javascript code will still be executed in one thread. Here is how it would work in practice.
In case of time out, browser will create a separate thread to wait for time out to expire or use some other mechanism to implement actual timing logic. Then timeout expires, the message will be placed on main event queue that tells the runtime to execute your handler. and that will happen as soon as message is picked up by main thread.
AJAX request would work similarly. Some browser internal thread may actually connect to server and wait for the response and once response is available place appropriate message on main event queue so main thread executes the handler.
In all cases your code will get executed by main thread. This is not different from most other UI system except that browser hides that logic from you. On other platforms you may need to deal with separate threads and ensure execution of handlers on UI thread.
Putting it more simply than talking in terms of threads, in general (for the browsers I'm aware of) there will only be one block of JavaScript executing at any given time.
When you make an asynchronous Ajax request or call setTimeout or setInterval the browser may manage them in another thread, but the actual JS code in the callbacks will not execute until some point after the currently executing block of code finishes. It just gets queued up.
A simple test to demonstrate this is if you put a piece of relatively long running code after a setTimeout but in the same block:
setTimeout("alert('Timeout!');", 5);
alert("After setTimeout; before loop");
for (var i=0, x=0; i < 2000000; i++) { x += i };
alert("After loop");
If you run the above you'll see the "After setTimeout" alert, then there'll be a pause while the loop runs, then you'll see "After loop", and only after that will you see "Timeout!" - even though clearly much longer than 5ms has passed (especially if you take a while to close the first alert).
An often-quoted reason for the single-thread is that it simplifies the browser's job of rendering the page, because you don't get the situation of lots of different threads of JavaScript all trying to update the DOM at the same time.
Javascript is a language designed to be embedded. It can and has been used in programs that execute javascript concurrently on different operating threads. There isn't much demand for an embedded language to explicitly control the creation of new threads of execution, but it could certainly be done by providing a host object with the required capabilities. The WHATWG actually includes a justification for their decision not to push a standard concurrent execution capability for browsers.

Categories

Resources