Look at:





Js contradictory single threaded asynchrony

Js is a single thread, but what are setTImeout and setInterval? However, it is well known that JS is single threaded, but the setTimeout and setInterval functions in JS work well asynchronously as follows

123456setTimeout(function(){console.log(‘ if I run after 2s ‘)},2*1000); Console. log(‘ If synced, I will be blocked for 2s’)

The code above is pretty clear but the result is

Obviously, if our JS code were completely synchronized, the second print would block the first print for 2s, but it didn’t block the main thread, leaving it to continue.

Anyway, our JS is single-threaded, so how do those asynchronous operations work? The answer is our great multi-threaded Browser, yes, js is single-threaded, but browsers are multi-threaded ah!

When js reads the setTimeout function,js tells the browser, “Hey buddy, I have a time-consuming operation here. I can’t get you to help me.” Of course, the browser is delighted with the answer and starts a timer thread. So here’s the problem

123456setTimeout(function(){console.log(‘ if I run after 2s ‘)},0); Console. log(‘ If synced, I will be blocked for 2s’)

All I’m doing here is changing the time to 0 to guess what it will print

Well, let’s not keep it in suspense

WTF? Why I wait for 0s is almost not waiting for it why I still print after you

This is our js event loop queue

In js We all task synchronization (now) in the main thread to run Form the execution stack Outside the main thread We also have a special running asynchronous task queue (future) of our js code will first read the synchronization task execution stack And then on to read the asynchronous task in the task queue This process is called Event loop (Event Loop) When our asynchronous task is finished, an event will be inserted into the task queue waiting for JS to execute



In zepto, the $. Fn object has a ready function with setTimeout(fn,0);

$.fn = {
    ready: function(callback){
      // dont use "interactive"On IE <= 10 (it can fired premature) // // document.readyState: returns when the document document is loading"loading". Returns when the document has finished rendering but is loading the embedded resource"interactive"And raises the DOMContentLoaded event. Returns when the document has finished loading"complete"And raises the Load event. / / the document. The documentElement. DoScroll, IE has a characteristic of the methoddoScroll can check whether the DOM is loaded. This method reports an error when the page has not finished loading untildoWhen Scroll stops reporting an error, DOM loading is completeif (document.readyState === "complete"|| (document.readyState ! = ="loading" && !document.documentElement.doScroll))
        setTimeout(function(){callback($)}, 0else{// Listen for the removal event var handler =function() {
          document.removeEventListener("DOMContentLoaded", handler, false)
          window.removeEventListener("load", handler, false)
          callback($)
        }
        document.addEventListener("DOMContentLoaded", handler, false)
        window.addEventListener("load", handler, false)}returnthis; }},Copy the code

SetTimeout = 0; setTimeout = 0; setTimeout = 0;

1. The browser kernel is multi-threaded, and they work together under the control of the kernel to keep synchronization. A browser usually consists of the following resident threads: GUI rendering thread, javascript engine thread, browser event trigger thread, timed trigger thread, and asynchronous HTTP request thread.

  • GUI rendering thread: Responsible for rendering the HTML elements of the browser interface, which is executed when the interface needs to be repainted or reflow due to some action. While the Javascript engine runs the script, the GUI rendering thread is suspended, that is, “frozen.” The GUI rendering thread and the JS engine are mutually exclusive, the GUI thread is suspended when the JS engine executes, and GUI updates are stored in a queue until the JS engine is idle.
  • Javascript engine threads: Also known as JS cores, are responsible for processing javascript scripts, such as the V8 engine. Javascript engine threads are, of course, responsible for parsing Javascript scripts and running code. The browser has only one JS thread running the JS program at any one time.
  • Browser event-triggering thread: When an event is triggered, this thread adds the event to the end of the queue, waiting for the JS engine to process it. These events can be currently executing code blocks such as scheduled tasks, or other threads from the browser kernel such as mouse clicks, AJAX asynchronous requests, etc., but due to the single-threaded nature of JS all these events have to queue up for the JS engine to process.
  • Timed trigger thread: The browser timed counter is not counted by the JavaScript engine, because JavaScript engines are single-threaded. If the JavaScript engine is blocked, the timing will be affected. Therefore, it is more reasonable to use a separate thread to time and trigger the timing.
  • Asynchronous HTTP request thread: When XMLHttpRequest opens a new thread through the browser after the connection and a state change is detected, if a callback function is set, the asynchronous thread generates a state change event and places it in the JavaScript engine’s processing queue for processing.

As an example, see how these threads work together:

Example 1: An asynchronous request is done by a threaded JavaScript execution thread, an HTTP request thread, and an event-firing thread. The JavaScript execution thread executes the asynchronous request code, at which point the browser opens a new HTTP request thread to execute the request, and the JavaScript execution thread continues to execute the remaining tasks in the execution queue. Then, at some point in the future, the event-triggering thread monitors that the previously initiated HTTP request has completed and inserts the completion callback code into the end of the JavaScript execution queue for processing when the JavaScript execution thread is idle.

Example 2: Timed triggers (setTimeout and setInterval) are timed counts executed by the browser’s timer thread and then inserted at the end of the timed handler at the end of the JavaScript execution queue (so with both functions, The actual execution time is greater than or equal to the specified time, and accurate timing is not guaranteed.

Javascript is single-threaded and can only do one thing at a time.

Let’s talk about the JS call stack, which can fundamentally understand the single thread execution process. Recommend a artifact site: Loupe can be used to graph the process of calling the stack, we can run the example on the site, good to go crazy.

Js Call stack: When a function is called, it is added to the top of the stack and removed from the top of the stack at the end of execution. The key to this data structure is LIFO (last-in, first-out).

Example: from (Concurrency model and Event Loop)



function f(b) {
    var a = 12;
    return a + b + 35;
}
function g(x) {
    var m = 4;
    return f(m * x);
}
g(21);Copy the code

When g is called, the first Heap stack frame is created, containing g’s parameters and local variables. When G calls f, a second stack frame is created and placed on top of the first, containing f’s arguments and local variables. When f returns, the topmost stack frame goes off the stack (the remaining stack frames for g function calls). When g returns, the stack is empty. Here’s another example:

function test() {
    setTimeout(function() {
        alert(1)
    },1000);
    alert(2);
}
test(a);Copy the code

If alert(1) is not setTimeout, then alert(1) is next, followed by alert(2). But now with setTimeout, alert(1) is added to a new stack to wait for 1s, so the actual result is alert(2), then alert(1).

Task queue (message queue) :

  • There are two types of functions: synchronous and asynchronous.

Synchronous function: A function is synchronous if the caller gets the expected result (that is, gets the expected return value or sees the expected effect) when function A returns.

Example:

console.log('Hi,'); When the function returns, you see what you expect: a string printed on the consoleCopy the code

Asynchronous function: if the caller does not get the expected result when function A returns, but needs to get it in the future by some means, then the function is asynchronous. Example:

setTimeout(fn, 1000); //setTimeout is the originating function of an asynchronous procedure, and fn is the callback function.Copy the code

  • There are two types of tasks: synchronous tasks and asynchronous tasks.

Synchronization task: a task that is queued to be executed on the main thread can be executed only after the previous task is completed. Asynchronous task: The main thread initiates an asynchronous request (that is, executes an asynchronous function), and the corresponding worker thread (browser event-triggering thread, asynchronous HTTP request thread, and so on) receives the request and tells the main thread that it received it (the asynchronous function returns); The main thread can continue to execute subsequent code while the worker thread performs asynchronous tasks; After the worker thread completes its work, it puts the completion message to the task (message) queue, and the main thread retrieves the task (message) through the event loop, and then performs some action (call the callback function).

The main thread is Stack and the task Queue is Queue.



  • Task queue: A task (message) queue is a first-in, first-out queue that holds various tasks (messages).
  • Event loop: The event loop refers to the process in which the main thread repeatedly fetches and executes tasks (messages) from the task (message) queue. The process of taking a task (message) and executing it is called a loop.

There is a reason for the word event in the event loop: Each message in the task (message) queue actually corresponds to an event — a DOM event. Example:

var button = document.getElement('#btn');
button.addEventListener('click'.function(e) { console.log(1); });Copy the code

From the point of view of asynchronous process, addEventListener function is the initiating function of asynchronous process, and event listener function is the callback function of asynchronous process. When the event is triggered, it indicates that the asynchronous task is complete. The event listener function is encapsulated into a message and placed in a message queue, waiting for the main thread to execute.

So what exactly is the task (message)? A task (message) is a callback function added when registering an asynchronous task. If an asynchronous function has no callback, it will not be placed in the task (message) queue.

To summarize the process: After executing all of the code in the current loop, the main thread takes a message from the task (message) queue and executes it. At this point, the worker thread notifies the main thread, and the callback is executed. If the main thread does not provide a callback function in the first place, there is no need for the worker thread to notify the main thread and thus place messages on the message queue.

Example: The worker thread is an asynchronous HTTP request thread, or Ajax thread



Finally, note that the callback function for the asynchronous procedure must not be executed in the current event loop. Instead, it is fetched from the task (message) queue when the main thread is empty.

Look at this picture again



When the main thread runs, the heap and stack are created, and the code in the stack calls various external apis that add various events (click, load, done) to the “task queue”. As soon as the stack completes, the main thread reads the “task queue” and executes the corresponding callback function for those events.

SetTimeout (fn, 0

Calling the setTimeout function adds a message to the queue after a time period has passed. This time period is passed in as the second argument to the function. If there are no other messages in the queue, the message is processed immediately. However, if there are other messages, the setTimeout message must wait for the other messages to finish processing. So the second parameter only represents the minimum time, not the exact time.

Zero delay does not mean that the callback will execute immediately. When setTimeout is called with zero delay, it does not execute the callback function immediately after the given interval. The wait time is based on the number of messages waiting in the queue. That is, setTimeout() simply inserts the event into the task queue and must wait until the current code (execution stack) completes before the main thread executes its specified callback function. If the current code takes a long time, it may take a long time, so there is no guarantee that the callback will be executed at setTimeout().

example

setTimeout(function() { console.log(1); }, 0); console.log(2)Copy the code

Result 2,1. Because only after the second line, the main thread is empty, the task queue will be fetched to execute the callback function.

Summary: setTimeout(fn,0) means to specify that a task should be executed at the earliest available free time on the main thread, that is, as early as possible. It adds an event to the end of the “task queue”, so it does not execute until the main thread has processed both the synchronized task and the existing events in the “task queue”. To some extent, we can use the setTimeout(fn,0) feature to correct the order of tasks in the browser.