7

image.png

1. JS is single-threaded, it does not mean that js has only one thread, but only one thread is working at the same time.

2. In js, besides the main thread, there are other threads, such as event loop thread, timer trigger thread, http asynchronous thread, browser event thread.

3. In the js main thread, it is divided into two sub-threads, the js engine thread and the GUI rendering thread. These two threads are mutually exclusive, and only one can execute at the same time, either executing js or rendering html

4. In the task queue, it is divided into macro tasks and micro tasks. Each time the task queue is executed, the micro task is executed first, and then the macro task is executed.

5. Usually macro tasks refer to callbacks such as setTimeout, setInterval, XMLHttprequest, and fetch. Microtasks refer to callbacks such as Promise and MutationObserver.

6. If there is no callback in the timer trigger thread, http asynchronous thread, and browser event thread, it will not be put into the queue.

7. The event loop thread must wait for the execution of the synchronization code in the main thread to end before going to the task queue to fetch another task and put it into the main thread for execution.

 //index.js
console.log('a');

  Promise.resolve().then(() => {
    console.log('b');
  });

  setTimeout(() => {
    console.log('c');
  }, 0);


  setTimeout(() => {
    console.log('d');

    Promise.resolve().then(() => {
      console.log('e');
    });
  }, 0);


  console.log('f');

The following is the execution logic of the above code:

  1. Encounter console.log('a'); Synchronous code, execute, output a;
  2. Encounter Promise, asynchronous code, put into task queue. And because it is the callback of promise, it belongs to micro-task. Flag microtask 1
  3. When setTimeout is executed, it is put into the customizer trigger thread, the timer trigger thread maintains when the countdown ends, and the callback is put into the task queue. And because the callback of setTimeout belongs to the macro task. Mark as macro task 1
  4. When the setTimeout is executed again, it is put into the customizer trigger thread, and the callback is put into the task queue. Because the callback of setTimeout belongs to the macro task. Mark as macro task 2
  5. Encounter console.log('f'); synchronous code, execute, output f

At this point, the synchronization code in the main thread has been completely executed, and the console outputs a, f. The main thread is empty. At this time, the event loop thread found that there are things in the task queue, namely micro task 1, macro task 1, and macro task 2.

  1. In accordance with the sequence of executing micro-tasks first, and then executing macro-tasks, first put micro-task 1, that is, () => { console.log('b'); } into the main thread to be executed by js. output b,
  2. At this time, the main thread is finished and empty again. At this time, there are macro task 1 and macro task 2 in the task queue. Since macro task 1 is put in first, it follows the first-in, first-out order of the queue. First put the macro task 1 into the main thread. i.e. () => { console.log('c'); }, output c,
  3. Then determine whether there are microtasks in the queue, and if so, execute them all. If not, continue with macro task 2.
  4. Put the macro task 2 into the main thread, i.e.

     () => {
     console.log('d');
    
     Promise.resolve().then(() => {
       console.log('e');
     });
    }

    Output d, encounter promise, asynchronous code, and put it into the microtask queue. Labeled as microtask 2. At this point the main thread is empty again.

  5. At this time, there is only microtask 2 in the task queue, and there are no other macrotasks and microtasks. Finally, execute microtask 2. i.e. () => { console.log('e'); }, output e

To sum up: The final output is afbcde

Notice:
1. The above setTimeout(()=>{}); belongs to synchronous code and will be executed. If let timer = setTimeout(()=>{}); you will find that the timer has a value and is a number. But it only returns the reference after executing setTimeout, and the remaining countdown and callback. All are maintained in the timer trigger thread.
2. Similarly, the above Promise.resolve() is also a synchronous code, let p = Promise.resolve() . You will find that p has a value and is a Promise object, but it only returns the reference after Promise.resolve() is executed. Callbacks in the remaining then. are maintained in the microtask queue

The above is a little bit of my own thoughts after reading other articles, plus my own understanding and local debugging. If there is a problem, please correct me.


寒水寺一禅
2.3k 声望119 粉丝

人生短短急个球!